]> git.mxchange.org Git - simgear.git/blobdiff - simgear/nasal/parse.c
Remove unneeded inclusions of windows.h, GL.h and GLU.H
[simgear.git] / simgear / nasal / parse.c
index f69d37b307ec05ca41fb610e08470a9e21371291..6da9a23b21915413d064184785c1aef01e69a34c 100644 (file)
@@ -1,12 +1,11 @@
 #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;
@@ -14,7 +13,8 @@ struct precedence {
     { { TOK_SEMI, TOK_COMMA },                 PREC_REVERSE },
     { { 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  },
@@ -31,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);
 }
 
@@ -204,11 +206,83 @@ 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) {
@@ -227,7 +301,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
             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);
@@ -278,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:
@@ -286,8 +360,8 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
                 addSemi = 1;
             break;
         }
-        if(t->next && t->next->type == TOK_SEMI)
-            addSemi = 0; // don't bother if it's already there!
+        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;
@@ -296,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
         }
@@ -323,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);
@@ -454,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;
@@ -502,12 +579,12 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
     struct Parser p;
 
     // Protect from garbage collection
-    naVec_append(c->temps, srcFile);
+    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();
     }
@@ -535,9 +612,7 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
 
     // Clean up our mess
     naParseDestroy(&p);
-    naVec_append(c->temps, codeObj);
+    naTempSave(c, codeObj);
 
     return codeObj;
 }
-
-