Frage

Ich arbeite an einer JavaScript-Zusammentragmaschine / Compositor in Java implementiert. Es funktioniert, aber es hat einen besseren Weg, um es zu implementieren und ich denke, ein Lexer der richtige Weg sein kann, aber ich bin ein wenig unscharf.

Ich habe eine Meta-Syntax für den Compositor entwickelt, die eine Teilmenge der JavaScript-Sprache ist. Soweit ein typisches JavaScript-Interpreter betrifft, so ist die Compositor Meta-Syntax legal, nur nicht funktionsfähig (I Synonyme zu reservierte Worte bin mit als Etikett von Codeblöcken gefolgt, die der Setzer soll interpretieren). Gerade jetzt, ich bin mit einem Scanner und regex die Meta-Syntax in Quelldateien zu finden, die dann ein flaches tut lexikalische basierend auf der Erfassung von Recht Ausdrücke verwandeln.

Es gibt eine enge Kopplung zwischen dem neu geschrieben Javascript und dem Scanner / Parser, die ich nicht zufrieden bin, wie die neu geschrieben uses Javascript eines Objektträgers Bibliothek verfügt über speziell für diesen Zweck geschrieben, und diese Bibliothek ist Änderungen vorbehalten.

Ich hoffe, dass ich in Backaus-Naur oder EBNF nur die Meta-Syntax deklarieren kann, ihn an einem Lexer (ANTRL?), Und auf der Basis von Meta-Ausdrücke Syntax in Quelldateien erkannt wird, leiten die Compositor auf bestimmte Aktionen, wie zum Beispiel ein erforderliches Skript zum anderen vorangestellt wird, eine Variable, Erzeugen von Text für eine geeignet parametrisiert Bibliothek Funktionsaufruf oder sogar Komprimieren eines Skripts deklarieren.

Ist dies der geeignete Weg, um einen Setzer zu machen? Soll ich sogar einen Scanner / Parser / Lexer Ansatz JavaScript Compositing verwenden? Jedes Feedback appreciated- Ich bin mir nicht ganz sicher, wo ich anfangen soll:)

UPDATE: Hier ist eine konkrete Beispiel- Beispielobjektdeklaration mit Meta-Syntax:

namespace: ie.ondevice
{
    use: ie.ondevice.lang.Mixin;
    use: ie.ondevice.TraitsDeclaration;

    declare: Example < Mixin | TraitsDeclaration
    {
        include: "path/to/file.extension";
        // implementation here
    }
 }

Dieses beschreibt das Objekt ie.ondevice.Example, dass inherits Mixin und ähnelt (d ‚implementiert die gleichen Funktionen und Merkmale wie‘) TraitsDeclaration. Der Setzer würde die Verwendung Aussagen erkennen und fehlschlagen, wenn der Namespace auf einen gültige Datei Standort Karte nicht oder voranstellen sonst die Skripte in dem Objekt Erklärungen residieren, dort Vorverarbeitung Meta-Syntax vor Sortierung.

Die Rewrite-Regeln in Bezug auf den Objektträger Bibliothek ausgedrückt erwähnte ich in einer Datei zur Folge hätte, dass können sieht wie folgt aus (ich eine Reihe von Möglichkeiten entwickelt haben, das Objekt zum Ausdruck bringen):

module("ie.ondevice.Example", function (mScope)
{
   // mScope is a delegate
   mScope.use("ie.ondevice.lang.Mixin");
   mScope.use("ie.ondevice.TraitsDeclaration");

   // As a result of two use statements, the mScope.localVars string would
   // would look like this: "var Mixin= ie.ondevice.lang.Mixin, TraitsDeclaration= ie.ondevice.TraitsDeclaration
   // by evaling we introduce 'imported' objects with their 'local'names
   eval(mScope.localVars); 

   // Function.prototype has been extended with the functions
   // inherits, define, defineStatic, resembles and getName

   // Prototypal inheritance using an anonymous bridge constructor
   Example.inherits(Mixin);

   // named methods and properties are added to Example.prototype
   Example.define
   (
       // functions and other properties
   );
   // ensures that Example.prototype has all the same
   // property names and types as TraitsDeclaration.prototype
   // throwing an exception if not the case.
   // This is optionally turned off for production- these
   // operations are only performed when the object is declared
   // - instantiation incurs no additional overhead
   Example.resembles(TraitsDeclaration);

   // constructor
   function Example ()
   {
       Mixin.call(this);
   };

   // will generate the ie.ondevice object hierarchy if required
   // and avail the constructor to it
   mScope.exports(Example);
 });

Vielleicht ist meine Anforderungen über Architecting ich, aber was ich möchte wirklich ein Ereignis collator- Zuhörer angetrieben dann lose Richtlinie Erkennungen gekoppelt werden könnten.

War es hilfreich?

Lösung

Ja, Parser-Generator verwendet (wie ANTLR ) ist der Weg, IMO zu gehen. Wenn Sie ein konkreteres Beispiel für das, was es ist, Sie zu parsen sind versuchen, vielleicht I (oder jemand anderes) können Sie weiter helfen.

Scott Stanchfield ein paar gute Video-Tutorials für ANTLR von Start der Anfang.

EDIT:

Bei Ihrem Beispiel:

namespace: ie.ondevice
{
    use: ie.ondevice.lang.Mixin;
    use: ie.ondevice.TraitsDeclaration;

    declare: Example < Mixin | TraitsDeclaration
    {
        include: "path/to/file.extension";
        // implementation here
    }
}

hier ist, wie eine Grammatik (für ANTLR) aussehen könnte:

parse
    :   'namespace' ':' packageOrClass '{'
            useStatement*
            objDeclaration
        '}'
    ;

useStatement
    :    'use' ':' packageOrClass ';'
    ;

includeStatement
    :    'include' ':' StringLiteral ';'
    ;

objDeclaration
    :    'declare' ':' Identifier ( '<' packageOrClass )? ( '|' packageOrClass )* '{' 
             includeStatement* 
         '}'
    ;

packageOrClass
    :    ( Identifier ( '.' Identifier )* )
    ;

StringLiteral
    :    '"' ( '\\\\' | '\\"' | ~( '"' | '\\' ) )* '"'
    ;

Identifier
    :    ( 'a'..'z' | 'A'..'Z' | '_' ) ( 'a'..'z' | 'A'..'Z' | '_' | '0'..'9' )*    
    ;

LineComment
    :    '//' ~( '\r' | '\n' )* ( '\r'? '\n' | EOF )     
    ;

Spaces
    :    ( ' ' | '\t' | '\r' | '\n' )     
    ;

Das oben genannte ist eine gemischte Grammatik (ANTLR wird sowohl die Lexer und Parser erzeugen). Die „Regeln“, beginnend mit einem Kapital sind Lexer-Regeln und die, die mit einem kleinen Start sind Parser-Regeln.

Nun könnte man die erzeugte Parser lassen erstellen FJSObject (Fuzzy JavaScript Object):

class FJSObject {

    String name;
    String namespace;
    String inherit;
    List<String> use;
    List<String> include;
    List<String> resemble;

    FJSObject() {
        use = new ArrayList<String>();
        include = new ArrayList<String>();
        resemble = new ArrayList<String>();
    }

    @Override
    public String toString() {
        StringBuilder b = new StringBuilder();
        b.append("name      : ").append(name).append('\n');
        b.append("namespace : ").append(namespace).append('\n');
        b.append("inherit   : ").append(inherit).append('\n');
        b.append("resemble  : ").append(resemble).append('\n');
        b.append("use       : ").append(use).append('\n');
        b.append("include   : ").append(include);
        return b.toString();
    }
}

und während Parser durch den Token-Strom geht, ist es einfach "füllt" FJSObject 's Variablen. Sie können durch das Einwickeln { und } um es klar, Java-Code in der Grammatik einbetten. Hier ein Beispiel:

grammar FJS;

@parser::members {FJSObject obj = new FJSObject();}

parse
    :   'namespace' ':' p=packageOrClass {obj.namespace = $p.text;}
        '{'
            useStatement*
            objDeclaration
        '}'
    ;

useStatement
    :   'use' ':' p=packageOrClass {obj.use.add($p.text);} ';'
    ;

includeStatement
    :   'include' ':' s=StringLiteral {obj.include.add($s.text);} ';'
    ;

objDeclaration
    :   'declare' ':' i=Identifier {obj.name = $i.text;} 
        ( '<' p=packageOrClass {obj.inherit = $p.text;} )? 
        ( '|' p=packageOrClass {obj.resemble.add($p.text);} )* 
        '{' 
            includeStatement* 
            // ...
        '}'
    ;

packageOrClass
    :   ( Identifier ( '.' Identifier )* )
    ;

StringLiteral
    :   '"' ( '\\\\' | '\\"' | ~( '"' | '\\' ) )* '"'
    ;

Identifier
    :   ( 'a'..'z' | 'A'..'Z' | '_' ) ( 'a'..'z' | 'A'..'Z' | '_' | '0'..'9' )* 
    ;

LineComment
    :   '//' ~( '\r' | '\n' )* ( '\r'? '\n' | EOF ) {skip();} // ignoring these tokens
    ;

Spaces
    :   ( ' ' | '\t' | '\r' | '\n' ) {skip();} // ignoring these tokens
    ;

Speichern Sie die oben in einer Datei namens FJS.g, herunterladen ANTLR und lassen es generieren Ihre Lexer & Parser wie folgt aus:

java -cp antlr-3.2.jar org.antlr.Tool FJS.g

Und um es zu testen, führen Sie dies:

public class ANTLRDemo {
    public static void main(String[] args) throws Exception {
        String source =
                "namespace: ie.ondevice                             \n"+
                "{                                                  \n"+
                "    use: ie.ondevice.lang.Mixin;                   \n"+
                "    use: ie.ondevice.TraitsDeclaration;            \n"+
                "                                                   \n"+
                "    declare: Example < Mixin | TraitsDeclaration   \n"+
                "    {                                              \n"+
                "        include: \"path/to/file.extension\";       \n"+
                "        // implementation here                     \n"+
                "    }                                              \n"+
                "}                                                    ";
        ANTLRStringStream in = new ANTLRStringStream(source);
        CommonTokenStream tokens = new CommonTokenStream(new FJSLexer(in));
        FJSParser parser = new FJSParser(tokens);
        parser.parse();
        System.out.println(parser.obj);
    }
} 

, die produzieren sollte die folgenden:

name      : Example
namespace : ie.ondevice
inherit   : Mixin
resemble  : [TraitsDeclaration]
use       : [ie.ondevice.lang.Mixin, ie.ondevice.TraitsDeclaration]
include   : ["path/to/file.extension"]

Nun könnte man die FJSObject Klasse lassen generieren / neu schreiben Ihre Meta / Quelldateien. Von dieser Klasse können Sie auch überprüft, um zu sehen, ob eine Datei enthalten tatsächlich vorhanden ist.

HTH.

Andere Tipps

Möchten Sie folgendes den Blick in Mozilla Rhino Projekt - es ist eine vollständige Lösung für das Laufen JavaScript auf der JVM, aber der Code zu analysieren ist JavaScript-Code ziemlich gut enapsulated und kann ohne die volle Funktionalität der Ausführung verwendet werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top