]> git.mxchange.org Git - simgear.git/blobdiff - simgear/nasal/parse.c
easyxml.cxx: add missing endXML visitor call
[simgear.git] / simgear / nasal / parse.c
index a17452c49c707a9760ef5b99489a84422d51b79b..6da9a23b21915413d064184785c1aef01e69a34c 100644 (file)
@@ -1,25 +1,27 @@
 #include <setjmp.h>
+#include <string.h>
 
 #include "parse.h"
 
 // Static precedence table, from low (loose binding, do first) to high
 // (tight binding, do last).
-enum { PREC_BINARY, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
-
-#define MAX_PREC_TOKS 5
+#define MAX_PREC_TOKS 6
 struct precedence {
     int toks[MAX_PREC_TOKS];
     int rule;
 } PRECEDENCE[] = {
     { { TOK_SEMI, TOK_COMMA },                 PREC_REVERSE },
-    { { TOK_COLON },                           PREC_BINARY },
+    { { TOK_ELLIPSIS },                        PREC_SUFFIX  },
     { { TOK_RETURN, TOK_BREAK, TOK_CONTINUE }, PREC_PREFIX  },
-    { { TOK_ASSIGN },                          PREC_REVERSE },
+    { { TOK_ASSIGN, TOK_PLUSEQ, TOK_MINUSEQ,
+        TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ     }, PREC_REVERSE },
+    { { TOK_COLON, TOK_QUESTION },             PREC_REVERSE },
+    { { TOK_VAR },                             PREC_PREFIX  },
     { { TOK_OR },                              PREC_BINARY  },
     { { TOK_AND },                             PREC_BINARY  },
     { { TOK_EQ, TOK_NEQ },                     PREC_BINARY  },
     { { TOK_LT, TOK_LTE, TOK_GT, TOK_GTE },    PREC_BINARY  },
-    { { TOK_PLUS, TOK_MINUS, TOK_CAT },        PREC_REVERSE  },
+    { { TOK_PLUS, TOK_MINUS, TOK_CAT },        PREC_BINARY  },
     { { TOK_MUL, TOK_DIV },                    PREC_BINARY  },
     { { TOK_MINUS, TOK_NEG, TOK_NOT },         PREC_PREFIX  },
     { { TOK_LPAR, TOK_LBRA },                  PREC_SUFFIX  },
@@ -29,8 +31,10 @@ struct precedence {
 
 void naParseError(struct Parser* p, char* msg, int line)
 {
+    // Some errors (e.g. code generation of a null pointer) lack a
+    // line number, so we throw -1 and set the line earlier.
+    if(line > 0) p->errLine = line;
     p->err = msg;
-    p->errLine = line;
     longjmp(p->jumpHandle, 1);
 }
 
@@ -202,22 +206,102 @@ static struct Token* emptyToken(struct Parser* p)
     return t;
 }
 
+// Synthesize a curly brace token to wrap token t foward to the end of
+// "statement".  FIXME: unify this with the addNewChild(), which does
+// very similar stuff.
+static void embrace(struct Parser* p, struct Token* t)
+{
+    struct Token *b, *end = t;
+    if(!t) return;
+    while(end->next) {
+        if(end->next->type == TOK_SEMI) {
+            // Slurp up the semi, iff it is followed by an else/elsif,
+            // otherwise leave it in place.
+            if(end->next->next) {
+                if(end->next->next->type == TOK_ELSE)  end = end->next;
+                if(end->next->next->type == TOK_ELSIF) end = end->next;
+            }
+            break;
+        }
+        if(end->next->type == TOK_COMMA) break;
+        if(end->next->type == TOK_ELSE) break;
+        if(end->next->type == TOK_ELSIF) break;
+        end = end->next;
+    }
+    b = emptyToken(p);
+    b->type = TOK_LCURL;
+    b->line = t->line;
+    b->parent = t->parent;
+    b->prev = t->prev;
+    b->next = end->next;
+    b->children = t;
+    b->lastChild = end;
+    if(t->prev) t->prev->next = b;
+    else b->parent->children = b;
+    if(end->next) end->next->prev = b;
+    else b->parent->lastChild = b;
+    t->prev = 0;
+    end->next = 0;
+    for(; t; t = t->next)
+        t->parent = b;
+}
+
+#define NEXT(t) (t ? t->next : 0)
+#define TYPE(t) (t ? t->type : -1)
+
+static void fixBracelessBlocks(struct Parser* p, struct Token* t)
+{
+    // Find the end, and march *backward*
+    while(t && t->next) t = t->next;
+    for(/**/; t; t=t->prev) {
+        switch(t->type) {
+        case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
+        case TOK_IF: case TOK_ELSIF:
+            if(TYPE(NEXT(t)) == TOK_LPAR && TYPE(NEXT(NEXT(t))) != TOK_LCURL)
+                    embrace(p, t->next->next);
+            break;
+        case TOK_ELSE:
+            if(TYPE(NEXT(t)) != TOK_LCURL)
+                embrace(p, t->next);
+            break;
+        case TOK_FUNC:
+            if(TYPE(NEXT(t)) == TOK_LPAR) {
+                if(TYPE(NEXT(NEXT(t))) != TOK_LCURL)
+                    embrace(p, NEXT(NEXT(t)));
+            } else if(TYPE(NEXT(t)) != TOK_LCURL)
+                embrace(p, t->next);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
 // Fixes up parenting for obvious parsing situations, like code blocks
 // being the child of a func keyword, etc...
 static void fixBlockStructure(struct Parser* p, struct Token* start)
 {
     struct Token *t, *c;
+    fixBracelessBlocks(p, start);
     t = start;
     while(t) {
         switch(t->type) {
-        case TOK_ELSE: case TOK_FUNC:
+        case TOK_FUNC:
+            // Slurp an optional paren block containing an arglist, then
+            // fall through to parse the curlies...
+            if(t->next && t->next->type == TOK_LPAR) {
+                c = t->next;
+                addNewChild(t, c);
+                fixBlockStructure(p, c);
+            }
+        case TOK_ELSE: // and TOK_FUNC!
             // These guys precede a single curly block
             if(!t->next || t->next->type != TOK_LCURL) oops(p, t);
             c = t->next;
             addNewChild(t, c);
             fixBlockStructure(p, c);
             break;
-        case TOK_FOR: case TOK_FOREACH: case TOK_WHILE:
+        case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
         case TOK_IF: case TOK_ELSIF:
             // Expect a paren and then a curly
             if(!t->next || t->next->type != TOK_LPAR) oops(p, t);
@@ -268,7 +352,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
                || t->prev->type == TOK_LCURL)
                 addSemi = 1;
             break;
-        case TOK_FOR: case TOK_FOREACH: case TOK_WHILE:
+        case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
             addSemi = 1;
             break;
         case TOK_FUNC:
@@ -276,6 +360,8 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
                 addSemi = 1;
             break;
         }
+        if(!t->next || t->next->type == TOK_SEMI || t->next->type == TOK_COMMA)
+            addSemi = 0; // don't bother, no need
         if(addSemi) {
             struct Token* semi = emptyToken(p);
             semi->type = TOK_SEMI;
@@ -284,6 +370,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
             semi->prev = t;
             semi->parent = t->parent;
             if(semi->next) semi->next->prev = semi;
+            else semi->parent->lastChild = semi;
             t->next = semi;
             t = semi; // don't bother checking the new one
         }
@@ -311,7 +398,7 @@ static int isBlock(int t)
 {
     return t == TOK_IF  || t == TOK_ELSIF   || t == TOK_ELSE
         || t == TOK_FOR || t == TOK_FOREACH || t == TOK_WHILE
-        || t == TOK_FUNC;
+        || t == TOK_FUNC || t == TOK_FORINDEX;
 }
 
 static void precChildren(struct Parser* p, struct Token* t);
@@ -442,6 +529,8 @@ static struct Token* parsePrecedence(struct Parser* p,
     if(!top)
         return parsePrecedence(p, start, end, level+1);
 
+    top->rule = rule;
+
     if(left) {
         left->next = right;
         left->prev = 0;
@@ -489,10 +578,13 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
     struct Token* t;
     struct Parser p;
 
+    // Protect from garbage collection
+    naTempSave(c, srcFile);
+
     // Catch parser errors here.
     *errLine = 0;
     if(setjmp(p.jumpHandle)) {
-        c->error = p.err;
+        strncpy(c->error, p.err, sizeof(c->error));
         *errLine = p.errLine;
         return naNil();
     }
@@ -516,12 +608,11 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
     p.tree.lastChild = t;
 
     // Generate code!
-    codeObj = naCodeGen(&p, &(p.tree));
+    codeObj = naCodeGen(&p, &(p.tree), 0);
 
     // Clean up our mess
     naParseDestroy(&p);
+    naTempSave(c, codeObj);
 
     return codeObj;
 }
-
-