Usermode - Fixed GAS/NASM detection
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / parse.c
index 12f2674..e6d9694 100644 (file)
 #define WANT_TOKEN_STRINGS     1
 #include "tokens.h"
 #include "ast.h"
+#include "common.h"
 
 #define DEBUG  0
+#define        SUPPORT_BREAK_TAGS      1
 
 // === PROTOTYPES ===
-tAST_Script    *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const char *Filename);
-void   *Parse_FunctionDefinition(tAST_Script *Script, tSpiderVariant *Variant, tParser *Parser, int Type);
+ int   Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename);
+void   *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type);
 tAST_Node      *Parse_DoCodeBlock(tParser *Parser);
 tAST_Node      *Parse_DoBlockLine(tParser *Parser);
 tAST_Node      *Parse_GetVarDef(tParser *Parser, int Type);
@@ -42,9 +44,10 @@ void SyntaxAssert(tParser *Parser, int Have, int Want);
 void   SyntaxError(tParser *Parser, int bFatal, const char *Message, ...);
 
 #define SyntaxAssert(_parser, _have, _want) do { \
-       if( (_have) != (_want) ) { \
+       int have = (_have), want = (_want); \
+       if( (have) != (want) ) { \
                SyntaxError(Parser, 1, "Unexpected %s(%i), expecting %s(%i)\n", \
-                       csaTOKEN_NAMES[_have], _have, csaTOKEN_NAMES[_want], _want); \
+                       csaTOKEN_NAMES[have], have, csaTOKEN_NAMES[want], want); \
                return NULL; \
        } \
 }while(0)
@@ -58,14 +61,13 @@ void        SyntaxError(tParser *Parser, int bFatal, const char *Message, ...);
 /**
  * \brief Parse a buffer into a syntax tree
  */
-tAST_Script    *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const char *Filename)
+int Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename)
 {
        tParser parser = {0};
        tParser *Parser = &parser;      //< Keeps code consistent
-       tAST_Script     *ret;
        tAST_Node       *mainCode, *node;
         int    type;
-       tAST_Function   *fcn;
+       tScript_Function        *fcn;
        
        #if DEBUG >= 2
        printf("Parse_Buffer: (Variant=%p, Buffer=%p)\n", Variant, Buffer);
@@ -84,7 +86,6 @@ tAST_Script   *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const cha
        parser.Filename += sizeof(int); // Move filename
        parser.ErrorHit = 0;
        
-       ret = AST_NewScript();
        mainCode = AST_NewCodeBlock(&parser);
        
        // Give us an error fallback
@@ -92,24 +93,17 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const cha
        {
                AST_FreeNode( mainCode );
                
-               for(fcn = ret->Functions; fcn; )
+               for(fcn = Script->Functions; fcn; )
                {
-                       tAST_Node       *var;
-                       tAST_Function   *nextFcn;
-                       AST_FreeNode( fcn->Code );
-                       for(var = fcn->Arguments; var;)
-                       {
-                               tAST_Node       *nextVar = var->NextSibling;
-                               AST_FreeNode( var );
-                               var = nextVar;
-                       }
+                       tScript_Function        *nextFcn;
+                       
+                       AST_FreeNode( fcn->ASTFcn );
                        
                        nextFcn = fcn->Next;
                        free( fcn );
                        fcn = nextFcn;
                }
-               free(ret);
-               return NULL;
+               return -1;
        }
        
        // Parse the file!
@@ -129,7 +123,7 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const cha
                        // Define a function (pass on to the other function definition code)
                        case TOK_IDENT:
                                PutBack(Parser);
-                               if( Parse_FunctionDefinition(ret, Variant, Parser, type) == NULL )
+                               if( Parse_FunctionDefinition(Script, Parser, type) == NULL )
                                        longjmp(Parser->JmpTarget, -1);
                                break ;
                        // Define a variable
@@ -154,14 +148,14 @@ tAST_Script       *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const cha
                
                // Define a function
                case TOK_RWD_FUNCTION:
-                       if( !Variant->bDyamicTyped ) {
+                       if( !Script->Variant->bDyamicTyped ) {
                                SyntaxError(Parser, 1, "Dynamic functions are invalid in static mode");
                                longjmp(Parser->JmpTarget, -1);
                        }
                        
                        type = SS_DATATYPE_DYNAMIC;
                
-                       if( Parse_FunctionDefinition(ret, Variant, Parser, SS_DATATYPE_DYNAMIC) == NULL )
+                       if( Parse_FunctionDefinition(Script, Parser, SS_DATATYPE_DYNAMIC) == NULL )
                                longjmp(Parser->JmpTarget, -1);
                
                        break;
@@ -180,51 +174,66 @@ tAST_Script       *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const cha
                        longjmp(Parser->JmpTarget, -1);
        }
        
-       fcn = AST_AppendFunction( ret, "", SS_DATATYPE_INTEGER );
-       AST_SetFunctionCode( fcn, mainCode );
+       AST_AppendFunction( Script, "", SS_DATATYPE_INTEGER, NULL, mainCode );
        
        //printf("---- %p parsed as SpiderScript ----\n", Buffer);
        
-       return ret;
+       return 0;
 }
 
-void *Parse_FunctionDefinition(tAST_Script *Script, tSpiderVariant *Variant, tParser *Parser, int Type)
+void *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type)
 {
-       tAST_Function   *fcn;
        char    *name;
-        int    type;
+        int    rv;
+       tAST_Node       *first_arg, *last_arg, *code;
+       
+       last_arg = (void*)&first_arg;   // HACK
        
        SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
        
        name = strndup( Parser->TokenStr, Parser->TokenLen );
-       fcn = AST_AppendFunction( Script, name, Type );
        #if DEBUG
        printf("DefFCN %s\n", name);
        #endif
-       free(name);
        
        // Get arguments
        SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN );
        if( LookAhead(Parser) != TOK_PAREN_CLOSE )
        {
                do {
-                       type = SS_DATATYPE_DYNAMIC;
+                        int    type = SS_DATATYPE_DYNAMIC;
                        GetToken(Parser);
                        // Non dynamic typed variants must use data types
-                       if( !Variant->bDyamicTyped ) {
+                       if( !Script->Variant->bDyamicTyped ) {
                                TOKEN_GET_DATATYPE(type, Parser->Token);
                                GetToken(Parser);
                        }
-                       AST_AppendFunctionArg(fcn, Parse_GetVarDef(Parser, type)); 
+                       last_arg->NextSibling = Parse_GetVarDef(Parser, type);
+                       last_arg = last_arg->NextSibling;
+                       last_arg->NextSibling = NULL;
                }       while(GetToken(Parser) == TOK_COMMA);
        }
        else
                GetToken(Parser);
        SyntaxAssert(Parser, Parser->Token, TOK_PAREN_CLOSE );
+
+       code = Parse_DoCodeBlock(Parser);
+
+       rv = AST_AppendFunction( Script, name, Type, first_arg, code );
+
+       // Clean up argument definition nodes
+       {
+               tAST_Node       *nextarg;
+               for( ; first_arg; first_arg = nextarg )
+               {
+                       nextarg = first_arg->NextSibling;
+                       AST_FreeNode(first_arg);
+               }
+       }
+
+       free(name);
        
-       AST_SetFunctionCode( fcn, Parse_DoCodeBlock(Parser) );
-       
-       return fcn;
+       return rv == 0 ? (void*)1 : NULL;
 }
 
 /**
@@ -281,11 +290,39 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser)
                ret = AST_NewUniOp(Parser, NODETYPE_RETURN, Parse_DoExpr0(Parser));
                break;
        
+       // Break / Continue (end a loop / go to next iteration)
+       case TOK_RWD_CONTINUE:
+       case TOK_RWD_BREAK:
+               {
+                int    tok;
+               char    *ident = NULL;
+               tok = GetToken(Parser);
+               // Get the number of nesting levels to break
+               if(LookAhead(Parser) == TOK_IDENT)
+               {
+                       GetToken(Parser);
+                       ident = strndup(Parser->TokenStr, Parser->TokenLen);
+               }
+               // Get the action
+               switch(tok)
+               {
+               case TOK_RWD_BREAK:     ret = AST_NewBreakout(Parser, NODETYPE_BREAK, ident);   break;
+               case TOK_RWD_CONTINUE:  ret = AST_NewBreakout(Parser, NODETYPE_CONTINUE, ident);        break;
+               default:
+                       SyntaxError(Parser, 1, "BUG Unhandled break/continue (%s)",
+                               csaTOKEN_NAMES[tok]);
+                       return NULL;
+               }
+               if(ident)       free(ident);
+               }
+               break;
+       
        // Control Statements
        case TOK_RWD_IF:
                {
                tAST_Node       *cond, *true, *false = NULL;
                GetToken(Parser);       // eat the if
+               
                SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
                cond = Parse_DoExpr0(Parser);   // Get condition
                SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
@@ -302,8 +339,20 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser)
        
        case TOK_RWD_FOR:
                {
+               char    *tag = NULL;
                tAST_Node       *init=NULL, *cond=NULL, *inc=NULL, *code;
                GetToken(Parser);       // Eat 'for'
+               
+               #if SUPPORT_BREAK_TAGS
+               if(LookAhead(Parser) == TOK_LT)
+               {
+                       GetToken(Parser);
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
+                       tag = strndup(Parser->TokenStr, Parser->TokenLen);
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
+               }
+               #endif
+               
                SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
                
                if(LookAhead(Parser) != TOK_SEMICOLON)
@@ -322,31 +371,56 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser)
                SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
                
                code = Parse_DoCodeBlock(Parser);
-               ret = AST_NewLoop(Parser, init, 0, cond, inc, code);
+               ret = AST_NewLoop(Parser, tag, init, 0, cond, inc, code);
+               if(tag) free(tag);
                }
                return ret;
        
        case TOK_RWD_DO:
                {
+               const char      *tag = "";
                tAST_Node       *code, *cond;
                GetToken(Parser);       // Eat 'do'
+               
+               #if SUPPORT_BREAK_TAGS
+               if(LookAhead(Parser) == TOK_LT)
+               {
+                       GetToken(Parser);
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
+                       tag = strndup(Parser->TokenStr, Parser->TokenLen);
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
+               }
+               #endif
+               
                code = Parse_DoCodeBlock(Parser);
                SyntaxAssert( Parser, GetToken(Parser), TOK_RWD_WHILE );
                SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
                cond = Parse_DoExpr0(Parser);
                SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
-               ret = AST_NewLoop(Parser, AST_NewNop(Parser), 1, cond, AST_NewNop(Parser), code);
+               ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 1, cond, AST_NewNop(Parser), code);
                }
                break;
        case TOK_RWD_WHILE:
                {
+               const char      *tag = "";
                tAST_Node       *code, *cond;
                GetToken(Parser);       // Eat 'while'
+               
+               #if SUPPORT_BREAK_TAGS
+               if(LookAhead(Parser) == TOK_LT)
+               {
+                       GetToken(Parser);
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
+                       tag = strndup(Parser->TokenStr, Parser->TokenLen);
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
+               }
+               #endif
+               
                SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
                cond = Parse_DoExpr0(Parser);
                SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
                code = Parse_DoCodeBlock(Parser);
-               ret = AST_NewLoop(Parser, AST_NewNop(Parser), 0, cond, AST_NewNop(Parser), code);
+               ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 0, cond, AST_NewNop(Parser), code);
                }
                return ret;
        
@@ -756,10 +830,15 @@ tAST_Node *Parse_DoValue(tParser *Parser)
                GetToken(Parser);
                return AST_NewReal( Parser, atof(Parser->TokenStr) );
        
-       case TOK_IDENT: return Parse_GetIdent(Parser, 0);
-       case TOK_VARIABLE:      return Parse_GetVariable(Parser);
+       case TOK_IDENT:
+               return Parse_GetIdent(Parser, 0);
+       case TOK_VARIABLE:
+               return Parse_GetVariable(Parser);
+       case TOK_RWD_NULL:
+               GetToken(Parser);
+               return AST_NewNop(Parser);      // NODETYPE_NOP returns NULL
        case TOK_RWD_NEW:
-               GetToken(Parser);       // Omnomnom
+               GetToken(Parser);
                return Parse_GetIdent(Parser, 1);
 
        default:

UCC git Repository :: git.ucc.asn.au