Mini-Clojure-Interpreter mit SableCC bauen



  • Hi,
    der Clojure-Interpreter beschränkt sich auf das Rechnen. Also z. B. (+ 5 4 1) soll 10 ergeben. Momentan kann ich nur zwei Ausdrücke verarbeiten, also z. B. (+ 3 2) bzw. (+ 3 (+ 4 1)). Ich würde das gerne auf beliebige Ausdrücke erweitern wie (+ 1 3 4 5 6 7)

    Das ist meine Grammatik:

    Helpers
       digit = ['0'..'9'];
       space = ' ';
       newline = 10;
    
    Tokens
    
       lparen = '(';
       rparen = ')';
       plus   = '+';
       minus  = '-';
       times  = '*';
       div    = '/';
    
       number = digit+;
       number_array = (digit+ space digit+)+;
       whitespace = (space | newline)*;
    
    Ignored Tokens
       whitespace;
    
    Productions
    
       exp    = {term} term
              | {add} lparen plus exp term rparen
              | {subt} lparen minus exp term rparen
              ;
       term   = {factor} factor
              | {times} lparen times term factor rparen
              | {div} lparen div term factor rparen
              ;
       factor = {number} number
              | {nested} lparen exp rparen
              ;
    

    Ich habe number_array definiert und das in einer alten Version in factor hinzugefügt, aber es gab immer nur die letzte Zahl aus.

    Weiß jemand einen Ansatz? Danke im Voraus!

    L. G.,
    IBV



  • lparen plus exp term rparen

    Wieso exp term ? Das ist Cargo-Cult; das macht man normalerweise wegen der Rangfolge und Assoziativität, die du aber in Lisp gar nicht hast. Spricht irgendwas dagegen, da eine Folge von exp s zuzulassen? Ich kenne leider SableCC nicht und kann dir nicht vorschlagen, wie das aussehen könnte. In EBNF wäre es

    exp = ( + exp* )
    

    BTW das ganze lässt sich entscheidend vereinfachen, wenn du einsiehst, dass das alles nur Listen sind.



  • Bashar schrieb:

    exp = ( + exp* )
    

    Das lässt, soweit ich sehe, auch (+ ) und (+ 5) zu.
    Kompilieren tut die Grammatik jedenfalls, aber ich krieg das trotzdem nicht umgesetzt.

    Vorher wurde Addition so umgesetzt:

    public void caseAAddExp(AAddExp e) {
      e.getExp().apply(this);
      Eval right = new Eval();
      e.getTerm().apply(right);
      value += right.getValue();
    }
    

    Jetzt habe ich das so umgeschrieben:

    public void caseAAddExp(AAddExp e) {
          final List<PExp> exprs = e.getExp();
    
          final PExp first = exprs.get(0);
          first.apply(this);
    
          for (int i = 1; i < exprs.size(); ++i) {
    	      final Eval right = new Eval();
    	      final PExp expr = exprs.get(i);
    
    	      expr.apply(right);
    
    	      value += right.getValue();
          }
    }
    

    exp sieht nun so aus (subt habe ich erst mal beim Alten belassen)

    exp    = {term} term
              | {add} lparen plus exp* rparen
              | {subt} lparen minus exp term rparen
    

    Wenn ich versuche (+ 5 5) zu verarbeiten, erhalte ich folgenden Fehler:

    parser.ParserException: [1,4] expecting: '(', ')', number
    

    Das Witzige ist, dass Substraktion auch nicht mehr funktioniert, obwohl ich das nichts geändert habe. (- 5 5) führt zu folgendem Fehler:

    parser.ParserException: [1,4] expecting: '(', number
    

    Bashar schrieb:

    BTW das ganze lässt sich entscheidend vereinfachen, wenn du einsiehst, dass das alles nur Listen sind.

    Wie?

    L. G.,
    IBV



  • IBV schrieb:

    Bashar schrieb:

    exp = ( + exp* )
    

    Das lässt, soweit ich sehe, auch (+ ) und (+ 5) zu.

    Selbstverständlich. Wie in Lisp (und Clojure).

    exp sieht nun so aus (subt habe ich erst mal beim Alten belassen)

    exp    = {term} term
              | {add} lparen plus exp* rparen
              | {subt} lparen minus exp term rparen
    

    Wenn ich versuche (+ 5 5) zu verarbeiten, erhalte ich folgenden Fehler:

    parser.ParserException: [1,4] expecting: '(', ')', number
    

    Das 4. Zeichen, ist das das Leerzeichen in der Mitte? Sorry keine Ahnung, aber das sieht mir nicht so aus, als hätte es was mit der Produktion für exp zu tun. Hast du noch was anderes geändert?

    Bashar schrieb:

    BTW das ganze lässt sich entscheidend vereinfachen, wenn du einsiehst, dass das alles nur Listen sind.

    Wie?

    Alle Ausdrücke sind entweder "Atome", also Zahlen oder Symbole wie +, -, *, etc., oder sie sind Listen von der Form ( Atom Atom Atom... ) . Die Bedeutung einer List ergibt sich aus dem ersten Atom. Es ist also nicht wirklich sinnvoll, eine fette Grammatik mit allen möglichen Ausdrücken aufzustellen. Was ist dein Ziel, willst du eine Lisp-Implementation schreiben oder willst du mit Grammatiken und Parsergeneratoren rumspielen?


Anmelden zum Antworten