Usermode - Fixed GAS/NASM detection
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / parse.c
index 5622123..e6d9694 100644 (file)
@@ -5,15 +5,19 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdarg.h>
 #include <spiderscript.h>
 #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, char *Buffer);
+ 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);
@@ -25,6 +29,8 @@ tAST_Node     *Parse_DoExpr3(tParser *Parser);        // Bitwise Operators
 tAST_Node      *Parse_DoExpr4(tParser *Parser);        // Bit Shifts
 tAST_Node      *Parse_DoExpr5(tParser *Parser);        // Arithmatic
 tAST_Node      *Parse_DoExpr6(tParser *Parser);        // Mult & Div
+tAST_Node      *Parse_DoExpr7(tParser *Parser);        // Right Unary Operations
+tAST_Node      *Parse_DoExpr8(tParser *Parser);        // Left Unary Operations
 
 tAST_Node      *Parse_DoParen(tParser *Parser);        // Parenthesis (Always Last)
 tAST_Node      *Parse_DoValue(tParser *Parser);        // Values
@@ -32,23 +38,36 @@ tAST_Node   *Parse_DoValue(tParser *Parser);        // Values
 tAST_Node      *Parse_GetString(tParser *Parser);
 tAST_Node      *Parse_GetNumeric(tParser *Parser);
 tAST_Node      *Parse_GetVariable(tParser *Parser);
-tAST_Node      *Parse_GetIdent(tParser *Parser);
+tAST_Node      *Parse_GetIdent(tParser *Parser, int bObjectCreate);
 
 void   SyntaxAssert(tParser *Parser, int Have, int Want);
+void   SyntaxError(tParser *Parser, int bFatal, const char *Message, ...);
+
+#define SyntaxAssert(_parser, _have, _want) do { \
+       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); \
+               return NULL; \
+       } \
+}while(0)
+
+#define TODO(Parser, message...) do {\
+       fprintf(stderr, "TODO: "message);\
+       longjmp(Parser->JmpTarget, -1);\
+}while(0)
 
 // === CODE ===
 /**
  * \brief Parse a buffer into a syntax tree
  */
-tAST_Script    *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
+int Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename)
 {
        tParser parser = {0};
-       tParser *Parser = &parser;      //< Keeps code consitent
-       tAST_Script     *ret;
-       tAST_Node       *mainCode;
-       char    *name;
-       tAST_Function   *fcn;
+       tParser *Parser = &parser;      //< Keeps code consistent
+       tAST_Node       *mainCode, *node;
         int    type;
+       tScript_Function        *fcn;
        
        #if DEBUG >= 2
        printf("Parse_Buffer: (Variant=%p, Buffer=%p)\n", Variant, Buffer);
@@ -60,16 +79,34 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
        parser.CurLine = 1;
        parser.BufStart = Buffer;
        parser.CurPos = Buffer;
+       // hackery to do reference counting
+       parser.Filename = malloc(sizeof(int)+strlen(Filename)+1);
+       strcpy(parser.Filename + sizeof(int), Filename);
+       *(int*)(parser.Filename) = 0;   // Set reference count
+       parser.Filename += sizeof(int); // Move filename
+       parser.ErrorHit = 0;
        
-       ret = AST_NewScript();
-       mainCode = AST_NewCodeBlock();
+       mainCode = AST_NewCodeBlock(&parser);
        
+       // Give us an error fallback
        if( setjmp( parser.JmpTarget ) != 0 )
        {
                AST_FreeNode( mainCode );
-               return NULL;
+               
+               for(fcn = Script->Functions; fcn; )
+               {
+                       tScript_Function        *nextFcn;
+                       
+                       AST_FreeNode( fcn->ASTFcn );
+                       
+                       nextFcn = fcn->Next;
+                       free( fcn );
+                       fcn = nextFcn;
+               }
+               return -1;
        }
        
+       // Parse the file!
        while(Parser->Token != TOK_EOF)
        {
                switch( GetToken(Parser) )
@@ -79,78 +116,124 @@ tAST_Script       *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
                
                // Typed variables/functions
                case TOKEN_GROUP_TYPES:
-                       {
-                        int    tok, type;
                        TOKEN_GET_DATATYPE(type, Parser->Token);
                        
-                       tok = GetToken(Parser);
+                       switch(GetToken(Parser))
+                       {
                        // Define a function (pass on to the other function definition code)
-                       if( tok == TOK_IDENT ) {
-                               goto defFcn;
-                       }
+                       case TOK_IDENT:
+                               PutBack(Parser);
+                               if( Parse_FunctionDefinition(Script, Parser, type) == NULL )
+                                       longjmp(Parser->JmpTarget, -1);
+                               break ;
                        // Define a variable
-                       else if( tok == TOK_VARIABLE ) {
-                               AST_AppendNode( mainCode, Parse_GetVarDef(Parser, type) );
-                               SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
-                       }
-                       else {
-                               fprintf(stderr, "ERROR: Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n",
-                                       csaTOKEN_NAMES[tok]);
-                       }
+                       case TOK_VARIABLE:
+                               node = Parse_GetVarDef(Parser, type);
+                               if(!node)       longjmp(Parser->JmpTarget, -1);
+                               
+                               AST_AppendNode( mainCode, node );
+                               // Can't use SyntaxAssert because that returns
+                               if(GetToken(Parser) != TOK_SEMICOLON) {
+                                       SyntaxError(Parser, 1, "Unexpected %s, expected TOK_SEMICOLON",
+                                               csaTOKEN_NAMES[Parser->Token]);
+                                       longjmp(Parser->JmpTarget, -1);
+                               }
+                               break;
+                       default:
+                               SyntaxError(Parser, 1, "Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n",
+                                       csaTOKEN_NAMES[Parser->Token]);
+                               break;
                        }
                        break;
                
                // Define a function
                case TOK_RWD_FUNCTION:
-                       if( !Variant->bDyamicTyped ) {
-                               fprintf(stderr, "ERROR: Attempt to create a dynamic function\n");
+                       if( !Script->Variant->bDyamicTyped ) {
+                               SyntaxError(Parser, 1, "Dynamic functions are invalid in static mode");
                                longjmp(Parser->JmpTarget, -1);
                        }
-                       type = SS_DATATYPE_DYNAMIC;
-                       SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
-               defFcn:
-                       name = strndup( Parser->TokenStr, Parser->TokenLen );
-                       fcn = AST_AppendFunction( ret, name );
-                       #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;
-                                       GetToken(Parser);
-                                       // Non dynamic typed variants must use data types
-                                       if( !Variant->bDyamicTyped ) {
-                                               TOKEN_GET_DATATYPE(type, Parser->Token);
-                                               GetToken(Parser);
-                                       }
-                                       AST_AppendFunctionArg(fcn, Parse_GetVarDef(Parser, type)); 
-                               }       while(GetToken(Parser) == TOK_COMMA);
-                       }
-                       else
-                               GetToken(Parser);
-                       SyntaxAssert(Parser, Parser->Token, TOK_PAREN_CLOSE );
-                       
-                       AST_SetFunctionCode( fcn, Parse_DoCodeBlock(Parser) );
+                       type = SS_DATATYPE_DYNAMIC;
+               
+                       if( Parse_FunctionDefinition(Script, Parser, SS_DATATYPE_DYNAMIC) == NULL )
+                               longjmp(Parser->JmpTarget, -1);
+               
                        break;
                
+               // Ordinary Statement
                default:
                        PutBack(Parser);
-                       AST_AppendNode( mainCode, Parse_DoBlockLine(Parser) );
+                       node = Parse_DoBlockLine(Parser);
+                       if(!node)       longjmp(Parser->JmpTarget, -1);
+                       AST_AppendNode( mainCode, node );
                        break;
                }
+               
+               // Jump to error handler on error
+               if(Parser->ErrorHit)
+                       longjmp(Parser->JmpTarget, -1);
        }
        
-       fcn = AST_AppendFunction( ret, "" );
-       AST_SetFunctionCode( fcn, mainCode );
+       AST_AppendFunction( Script, "", SS_DATATYPE_INTEGER, NULL, mainCode );
        
-       printf("---- %p parsed as SpiderScript ----\n", Buffer);
+       //printf("---- %p parsed as SpiderScript ----\n", Buffer);
        
-       return ret;
+       return 0;
+}
+
+void *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type)
+{
+       char    *name;
+        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 );
+       #if DEBUG
+       printf("DefFCN %s\n", name);
+       #endif
+       
+       // Get arguments
+       SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN );
+       if( LookAhead(Parser) != TOK_PAREN_CLOSE )
+       {
+               do {
+                        int    type = SS_DATATYPE_DYNAMIC;
+                       GetToken(Parser);
+                       // Non dynamic typed variants must use data types
+                       if( !Script->Variant->bDyamicTyped ) {
+                               TOKEN_GET_DATATYPE(type, Parser->Token);
+                               GetToken(Parser);
+                       }
+                       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);
+       
+       return rv == 0 ? (void*)1 : NULL;
 }
 
 /**
@@ -159,13 +242,23 @@ tAST_Script       *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
 tAST_Node *Parse_DoCodeBlock(tParser *Parser)
 {
        tAST_Node       *ret;
-       SyntaxAssert(Parser, GetToken(Parser), TOK_BRACE_OPEN );
        
-       ret = AST_NewCodeBlock();
+       // Check if we are being called for a one-liner
+       if( GetToken(Parser) != TOK_BRACE_OPEN ) {
+               PutBack(Parser);
+               return Parse_DoBlockLine(Parser);
+       }
+       
+       ret = AST_NewCodeBlock(Parser);
        
        while( LookAhead(Parser) != TOK_BRACE_CLOSE )
        {
-               AST_AppendNode( ret, Parse_DoBlockLine(Parser) );
+               tAST_Node       *node = Parse_DoBlockLine(Parser);
+               if(!node) {
+                       AST_FreeNode(ret);
+                       return NULL;
+               }
+               AST_AppendNode( ret, node );
        }
        GetToken(Parser);       // Omnomnom
        return ret;
@@ -182,30 +275,161 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser)
        
        switch(LookAhead(Parser))
        {
+       // New block
+       case TOK_BRACE_OPEN:
+               return Parse_DoCodeBlock(Parser);
+       
+       // Empty statement
+       case TOK_SEMICOLON:
+               GetToken(Parser);
+               return NULL;
        
        // Return from a method
        case TOK_RWD_RETURN:
-               //printf("return\n");
                GetToken(Parser);
-               ret = AST_NewUniOp(NODETYPE_RETURN, Parse_DoExpr0(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:
-       //      break;
+       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);
+               true = Parse_DoCodeBlock(Parser);
+               if( LookAhead(Parser) == TOK_RWD_ELSE ) {
+                       GetToken(Parser);
+                       false = Parse_DoCodeBlock(Parser);
+               }
+               else
+                       false = AST_NewNop(Parser);
+               ret = AST_NewIf(Parser, cond, true, false);
+               }
+               return ret;
+       
+       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)
+                       init = Parse_DoExpr0(Parser);
+               
+               SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
+               
+               if(LookAhead(Parser) != TOK_SEMICOLON)
+                       cond = Parse_DoExpr0(Parser);
+               
+               SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
+               
+               if(LookAhead(Parser) != TOK_PAREN_CLOSE)
+                       inc = Parse_DoExpr0(Parser);
+               
+               SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
+               
+               code = Parse_DoCodeBlock(Parser);
+               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, 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, tag, AST_NewNop(Parser), 0, cond, AST_NewNop(Parser), code);
+               }
+               return ret;
        
        // Define Variables
        case TOKEN_GROUP_TYPES:
                {
                         int    type;
-                       
-                       switch(GetToken(Parser))
-                       {
-                       case TOK_RWD_INTEGER:   type = SS_DATATYPE_INTEGER;     break;
-                       case TOK_RWD_OBJECT:    type = SS_DATATYPE_OBJECT;      break;
-                       case TOK_RWD_REAL:      type = SS_DATATYPE_REAL;        break;
-                       case TOK_RWD_STRING:    type = SS_DATATYPE_STRING;      break;
-                       }
+                       GetToken(Parser);
+                       TOKEN_GET_DATATYPE(type, Parser->Token);
                        
                        SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE);
                        
@@ -238,14 +462,31 @@ tAST_Node *Parse_GetVarDef(tParser *Parser, int Type)
        memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
        name[Parser->TokenLen-1] = 0;
        // Define the variable
-       ret = AST_NewDefineVar(Type, name);
+       ret = AST_NewDefineVar(Parser, Type, name);
        // Handle arrays
        while( LookAhead(Parser) == TOK_SQUARE_OPEN )
        {
+               tAST_Node *node;
                GetToken(Parser);
-               AST_AppendNode(ret, Parse_DoExpr0(Parser));
+               node = Parse_DoExpr0(Parser);
+               if(!node) {
+                       AST_FreeNode(ret);
+                       return NULL;
+               }
+               AST_AppendNode(ret, node);
                SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
        }
+       
+       if( LookAhead(Parser) == TOK_ASSIGN )
+       {
+               GetToken(Parser);
+               ret->DefVar.InitialValue = Parse_DoExpr0(Parser);
+               if(!ret->DefVar.InitialValue) {
+                       AST_FreeNode(ret);
+                       return NULL;
+               }
+       }
+       
        return ret;
 }
 
@@ -254,32 +495,41 @@ tAST_Node *Parse_GetVarDef(tParser *Parser, int Type)
  */
 tAST_Node *Parse_DoExpr0(tParser *Parser)
 {
-       tAST_Node       *ret = Parse_DoExpr1(Parser);
+       #define _next   Parse_DoExpr1
+       tAST_Node       *ret = _next(Parser);
+        int    cont = 1;
 
-       // Check Assignment
-       switch(LookAhead(Parser))
+       while( cont )
        {
-       case TOK_ASSIGN:
-               GetToken(Parser);               // Eat Token
-               ret = AST_NewAssign(NODETYPE_NOP, ret, Parse_DoExpr0(Parser));
-               break;
-       #if 0
-       case TOK_DIV_EQU:
-               GetToken(Parser);               // Eat Token
-               ret = AST_NewAssign(NODETYPE_DIVIDE, ret, Parse_DoExpr0(Parser));
-               break;
-       case TOK_MULT_EQU:
-               GetToken(Parser);               // Eat Token
-               ret = AST_NewAssign(NODETYPE_MULTIPLY, ret, Parse_DoExpr0(Parser));
-               break;
-       #endif
-       default:
-               #if DEBUG >= 2
-               printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token);
-               #endif
-               break;
+               // Check Assignment
+               switch(GetToken(Parser))
+               {
+               case TOK_ASSIGN:
+                       ret = AST_NewAssign(Parser, NODETYPE_NOP, ret, _next(Parser));
+                       break;
+               case TOK_ASSIGN_DIV:
+                       ret = AST_NewAssign(Parser, NODETYPE_DIVIDE, ret, _next(Parser));
+                       break;
+               case TOK_ASSIGN_MUL:
+                       ret = AST_NewAssign(Parser, NODETYPE_MULTIPLY, ret, _next(Parser));
+                       break;
+               case TOK_ASSIGN_PLUS:
+                       ret = AST_NewAssign(Parser, NODETYPE_ADD, ret, _next(Parser));
+                       break;
+               case TOK_ASSIGN_MINUS:
+                       ret = AST_NewAssign(Parser, NODETYPE_SUBTRACT, ret, _next(Parser));
+                       break;
+               default:
+                       #if DEBUG >= 2
+                       printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token);
+                       #endif
+                       PutBack(Parser);
+                       cont = 0;
+                       break;
+               }
        }
        return ret;
+       #undef _next
 }
 
 /**
@@ -287,24 +537,31 @@ tAST_Node *Parse_DoExpr0(tParser *Parser)
  */
 tAST_Node *Parse_DoExpr1(tParser *Parser)
 {
-       tAST_Node       *ret = Parse_DoExpr2(Parser);
-       
-       switch(GetToken(Parser))
+       #define _next   Parse_DoExpr2
+       tAST_Node       *ret = _next(Parser);
+        int    cont = 1;
+
+       while( cont )
        {
-       case TOK_LOGICAND:
-               ret = AST_NewBinOp(NODETYPE_LOGICALAND, ret, Parse_DoExpr1(Parser));
-               break;
-       case TOK_LOGICOR:
-               ret = AST_NewBinOp(NODETYPE_LOGICALOR, ret, Parse_DoExpr1(Parser));
-               break;
-       case TOK_LOGICXOR:
-               ret = AST_NewBinOp(NODETYPE_LOGICALXOR, ret, Parse_DoExpr1(Parser));
-               break;
-       default:
-               PutBack(Parser);
-               break;
+               switch(GetToken(Parser))
+               {
+               case TOK_LOGICAND:
+                       ret = AST_NewBinOp(Parser, NODETYPE_LOGICALAND, ret, _next(Parser));
+                       break;
+               case TOK_LOGICOR:
+                       ret = AST_NewBinOp(Parser, NODETYPE_LOGICALOR, ret, _next(Parser));
+                       break;
+               case TOK_LOGICXOR:
+                       ret = AST_NewBinOp(Parser, NODETYPE_LOGICALXOR, ret, _next(Parser));
+                       break;
+               default:
+                       PutBack(Parser);
+                       cont = 0;
+                       break;
+               }
        }
        return ret;
+       #undef _next
 }
 
 // --------------------
@@ -312,25 +569,38 @@ tAST_Node *Parse_DoExpr1(tParser *Parser)
 // --------------------
 tAST_Node *Parse_DoExpr2(tParser *Parser)
 {
-       tAST_Node       *ret = Parse_DoExpr3(Parser);
+       #define _next   Parse_DoExpr3
+       tAST_Node       *ret = _next(Parser);
+        int    cont = 1;
 
-       // Check token
-       switch(GetToken(Parser))
+       while( cont )
        {
-       case TOK_EQUALS:
-               ret = AST_NewBinOp(NODETYPE_EQUALS, ret, Parse_DoExpr2(Parser));
-               break;
-       case TOK_LT:
-               ret = AST_NewBinOp(NODETYPE_LESSTHAN, ret, Parse_DoExpr2(Parser));
-               break;
-       case TOK_GT:
-               ret = AST_NewBinOp(NODETYPE_GREATERTHAN, ret, Parse_DoExpr2(Parser));
-               break;
-       default:
-               PutBack(Parser);
-               break;
+               // Check token
+               switch(GetToken(Parser))
+               {
+               case TOK_EQUALS:
+                       ret = AST_NewBinOp(Parser, NODETYPE_EQUALS, ret, _next(Parser));
+                       break;
+               case TOK_LT:
+                       ret = AST_NewBinOp(Parser, NODETYPE_LESSTHAN, ret, _next(Parser));
+                       break;
+               case TOK_GT:
+                       ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHAN, ret, _next(Parser));
+                       break;
+               case TOK_LTE:
+                       ret = AST_NewBinOp(Parser, NODETYPE_LESSTHANEQUAL, ret, _next(Parser));
+                       break;
+               case TOK_GTE:
+                       ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHANEQUAL, ret, _next(Parser));
+                       break;
+               default:
+                       PutBack(Parser);
+                       cont = 0;
+                       break;
+               }
        }
        return ret;
+       #undef _next
 }
 
 /**
@@ -338,25 +608,32 @@ tAST_Node *Parse_DoExpr2(tParser *Parser)
  */
 tAST_Node *Parse_DoExpr3(tParser *Parser)
 {
-       tAST_Node       *ret = Parse_DoExpr4(Parser);
+       #define _next   Parse_DoExpr4
+       tAST_Node       *ret = _next(Parser);
+        int    cont = 1;
 
-       // Check Token
-       switch(GetToken(Parser))
+       while( cont )
        {
-       case TOK_OR:
-               ret = AST_NewBinOp(NODETYPE_BWOR, ret, Parse_DoExpr3(Parser));
-               break;
-       case TOK_AND:
-               ret = AST_NewBinOp(NODETYPE_BWAND, ret, Parse_DoExpr3(Parser));
-               break;
-       case TOK_XOR:
-               ret = AST_NewBinOp(NODETYPE_BWXOR, ret, Parse_DoExpr3(Parser));
-               break;
-       default:
-               PutBack(Parser);
-               break;
+               // Check Token
+               switch(GetToken(Parser))
+               {
+               case TOK_OR:
+                       ret = AST_NewBinOp(Parser, NODETYPE_BWOR, ret, _next(Parser));
+                       break;
+               case TOK_AND:
+                       ret = AST_NewBinOp(Parser, NODETYPE_BWAND, ret, _next(Parser));
+                       break;
+               case TOK_XOR:
+                       ret = AST_NewBinOp(Parser, NODETYPE_BWXOR, ret, _next(Parser));
+                       break;
+               default:
+                       PutBack(Parser);
+                       cont = 0;
+                       break;
+               }
        }
        return ret;
+       #undef _next
 }
 
 // --------------------
@@ -364,22 +641,29 @@ tAST_Node *Parse_DoExpr3(tParser *Parser)
 // --------------------
 tAST_Node *Parse_DoExpr4(tParser *Parser)
 {
-       tAST_Node *ret = Parse_DoExpr5(Parser);
+       #define _next   Parse_DoExpr5
+       tAST_Node *ret = _next(Parser);
+        int    cont = 1;
 
-       switch(GetToken(Parser))
+       while( cont )
        {
-       case TOK_SHL:
-               ret = AST_NewBinOp(NODETYPE_BITSHIFTLEFT, ret, Parse_DoExpr5(Parser));
-               break;
-       case TOK_SHR:
-               ret = AST_NewBinOp(NODETYPE_BITSHIFTRIGHT, ret, Parse_DoExpr5(Parser));
-               break;
-       default:
-               PutBack(Parser);
-               break;
+               switch(GetToken(Parser))
+               {
+               case TOK_SHL:
+                       ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTLEFT, ret, _next(Parser));
+                       break;
+               case TOK_SHR:
+                       ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTRIGHT, ret, _next(Parser));
+                       break;
+               default:
+                       PutBack(Parser);
+                       cont = 0;
+                       break;
+               }
        }
 
        return ret;
+       #undef _next
 }
 
 // --------------------
@@ -387,22 +671,32 @@ tAST_Node *Parse_DoExpr4(tParser *Parser)
 // --------------------
 tAST_Node *Parse_DoExpr5(tParser *Parser)
 {
-       tAST_Node *ret = Parse_DoExpr6(Parser);
-
-       switch(GetToken(Parser))
+       #define _next   Parse_DoExpr6
+       tAST_Node *ret = _next(Parser);
+        int    cont = 1;
+       
+       // While loop is added to ensure that the evaluation order ends up as
+       // right to left.
+       // E.g. a + b + c + d ends up as (((a + b) + c) + d) for casting
+       while( cont )
        {
-       case TOK_PLUS:
-               ret = AST_NewBinOp(NODETYPE_ADD, ret, Parse_DoExpr5(Parser));
-               break;
-       case TOK_MINUS:
-               ret = AST_NewBinOp(NODETYPE_SUBTRACT, ret, Parse_DoExpr5(Parser));
-               break;
-       default:
-               PutBack(Parser);
-               break;
+               switch(GetToken(Parser))
+               {
+               case TOK_PLUS:
+                       ret = AST_NewBinOp(Parser, NODETYPE_ADD, ret, _next(Parser));
+                       break;
+               case TOK_MINUS:
+                       ret = AST_NewBinOp(Parser, NODETYPE_SUBTRACT, ret, _next(Parser));
+                       break;
+               default:
+                       PutBack(Parser);
+                       cont = 0;
+                       break;
+               }
        }
 
        return ret;
+       #undef _next
 }
 
 // --------------------
@@ -410,24 +704,75 @@ tAST_Node *Parse_DoExpr5(tParser *Parser)
 // --------------------
 tAST_Node *Parse_DoExpr6(tParser *Parser)
 {
-       tAST_Node *ret = Parse_DoParen(Parser);
+       #define _next   Parse_DoExpr7
+       tAST_Node *ret = _next(Parser);
+        int    cont = 1;
+
+       while( cont )
+       {
+               switch(GetToken(Parser))
+               {
+               case TOK_MUL:
+                       ret = AST_NewBinOp(Parser, NODETYPE_MULTIPLY, ret, _next(Parser));
+                       break;
+               case TOK_DIV:
+                       ret = AST_NewBinOp(Parser, NODETYPE_DIVIDE, ret, _next(Parser));
+                       break;
+               default:
+                       PutBack(Parser);
+                       cont = 0;
+                       break;
+               }
+       }
 
+       return ret;
+       #undef _next
+}
+
+// --------------------
+// Expression 7 - Right Unary Operations
+// --------------------
+tAST_Node *Parse_DoExpr7(tParser *Parser)
+{
+       tAST_Node *ret = Parse_DoExpr8(Parser);
+       
        switch(GetToken(Parser))
        {
-       case TOK_MUL:
-               ret = AST_NewBinOp(NODETYPE_MULTIPLY, ret, Parse_DoExpr6(Parser));
+       case TOK_INCREMENT:
+               ret = AST_NewUniOp(Parser, NODETYPE_POSTINC, ret);
                break;
-       case TOK_DIV:
-               ret = AST_NewBinOp(NODETYPE_DIVIDE, ret, Parse_DoExpr6(Parser));
+       case TOK_DECREMENT:
+               ret = AST_NewUniOp(Parser, NODETYPE_POSTDEC, ret);
                break;
        default:
                PutBack(Parser);
                break;
        }
-
        return ret;
 }
 
+// --------------------
+// Expression 8 - Left Unary Operations
+// --------------------
+tAST_Node *Parse_DoExpr8(tParser *Parser)
+{
+       switch(GetToken(Parser))
+       {
+       case TOK_INCREMENT:
+               return AST_NewAssign(Parser, NODETYPE_ADD, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
+       case TOK_DECREMENT:
+               return AST_NewAssign(Parser, NODETYPE_SUBTRACT, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
+       case TOK_MINUS:
+               return AST_NewUniOp(Parser, NODETYPE_NEGATE, Parse_DoExpr8(Parser));
+       case TOK_LOGICNOT:
+               return AST_NewUniOp(Parser, NODETYPE_LOGICALNOT, Parse_DoExpr8(Parser));
+       case TOK_BWNOT:
+               return AST_NewUniOp(Parser, NODETYPE_BWNOT, Parse_DoExpr8(Parser));
+       default:
+               PutBack(Parser);
+               return Parse_DoParen(Parser);
+       }
+}
 
 // --------------------
 // 2nd Last Expression - Parens
@@ -440,12 +785,23 @@ tAST_Node *Parse_DoParen(tParser *Parser)
        if(LookAhead(Parser) == TOK_PAREN_OPEN)
        {
                tAST_Node       *ret;
+                int    type;
                GetToken(Parser);
                
                // TODO: Handle casts here
-               
-               ret = Parse_DoExpr0(Parser);
-               SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
+               switch(LookAhead(Parser))
+               {
+               case TOKEN_GROUP_TYPES:
+                       GetToken(Parser);
+                       TOKEN_GET_DATATYPE(type, Parser->Token);
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
+                       ret = AST_NewCast(Parser, type, Parse_DoParen(Parser));
+                       break;
+               default:                
+                       ret = Parse_DoExpr0(Parser);
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
+                       break;
+               }
                return ret;
        }
        else
@@ -465,10 +821,25 @@ tAST_Node *Parse_DoValue(tParser *Parser)
 
        switch(tok)
        {
-       case TOK_STR:   return Parse_GetString(Parser);
-       case TOK_INTEGER:       return Parse_GetNumeric(Parser);
-       case TOK_IDENT: return Parse_GetIdent(Parser);
-       case TOK_VARIABLE:      return Parse_GetVariable(Parser);
+       case TOK_STR:
+               return Parse_GetString(Parser);
+       case TOK_INTEGER:
+               return Parse_GetNumeric(Parser);
+       
+       case TOK_REAL:
+               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_RWD_NULL:
+               GetToken(Parser);
+               return AST_NewNop(Parser);      // NODETYPE_NOP returns NULL
+       case TOK_RWD_NEW:
+               GetToken(Parser);
+               return Parse_GetIdent(Parser, 1);
 
        default:
                fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n",
@@ -483,9 +854,35 @@ tAST_Node *Parse_DoValue(tParser *Parser)
 tAST_Node *Parse_GetString(tParser *Parser)
 {
        tAST_Node       *ret;
+        int    i, j;
        GetToken( Parser );
-       // TODO: Parse Escape Codes
-       ret = AST_NewString( Parser->TokenStr+1, Parser->TokenLen-2 );
+       
+       {
+               char    data[ Parser->TokenLen - 2 ];
+               j = 0;
+               
+               for( i = 1; i < Parser->TokenLen - 1; i++ )
+               {
+                       if( Parser->TokenStr[i] == '\\' ) {
+                               i ++;
+                               switch( Parser->TokenStr[i] )
+                               {
+                               case 'n':       data[j++] = '\n';       break;
+                               case 'r':       data[j++] = '\r';       break;
+                               default:
+                                       // TODO: Octal Codes
+                                       // TODO: Error/Warning?
+                                       break;
+                               }
+                       }
+                       else {
+                               data[j++] = Parser->TokenStr[i];
+                       }
+               }
+               
+               // TODO: Parse Escape Codes
+               ret = AST_NewString( Parser, data, j );
+       }
        return ret;
 }
 
@@ -494,10 +891,50 @@ tAST_Node *Parse_GetString(tParser *Parser)
  */
 tAST_Node *Parse_GetNumeric(tParser *Parser)
 {
-       uint64_t        value;
-       GetToken( Parser );
-       value = atoi( Parser->TokenStr );
-       return AST_NewInteger( value );
+       uint64_t        value = 0;
+       const char      *pos;
+       SyntaxAssert( Parser, GetToken( Parser ), TOK_INTEGER );
+       pos = Parser->TokenStr;
+       //printf("pos = %p, *pos = %c\n", pos, *pos);
+               
+       if( *pos == '0' )
+       {
+               pos ++;
+               if(*pos == 'x') {
+                       pos ++;
+                       for( ;; pos++)
+                       {
+                               value *= 16;
+                               if( '0' <= *pos && *pos <= '9' ) {
+                                       value += *pos - '0';
+                                       continue;
+                               }
+                               if( 'A' <= *pos && *pos <= 'F' ) {
+                                       value += *pos - 'A' + 10;
+                                       continue;
+                               }
+                               if( 'a' <= *pos && *pos <= 'f' ) {
+                                       value += *pos - 'a' + 10;
+                                       continue;
+                               }
+                               break;
+                       }
+               }
+               else {
+                       while( '0' <= *pos && *pos <= '7' ) {
+                               value = value*8 + *pos - '0';
+                               pos ++;
+                       }
+               }
+       }
+       else {
+               while( '0' <= *pos && *pos <= '9' ) {
+                       value = value*10 + *pos - '0';
+                       pos ++;
+               }
+       }
+       
+       return AST_NewInteger( Parser, value );
 }
 
 /**
@@ -511,35 +948,75 @@ tAST_Node *Parse_GetVariable(tParser *Parser)
                char    name[Parser->TokenLen];
                memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
                name[Parser->TokenLen-1] = 0;
-               ret = AST_NewVariable( name );
+               ret = AST_NewVariable( Parser, name );
                #if DEBUG >= 2
                printf("Parse_GetVariable: name = '%s'\n", name);
                #endif
        }
-       // Handle array references
-       while( LookAhead(Parser) == TOK_SQUARE_OPEN )
+       for(;;)
        {
                GetToken(Parser);
-               ret = AST_NewBinOp(NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
-               SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
+               if( Parser->Token == TOK_SQUARE_OPEN )
+               {
+                       ret = AST_NewBinOp(Parser, NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
+                       continue ;
+               }
+               if( Parser->Token == TOK_ELEMENT )
+               {
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
+                       // Method Call
+                       if( LookAhead(Parser) == TOK_PAREN_OPEN )
+                       {
+                               char    name[Parser->TokenLen+1];
+                               memcpy(name, Parser->TokenStr, Parser->TokenLen);
+                               name[Parser->TokenLen] = 0;
+                               ret = AST_NewMethodCall(Parser, ret, name);
+                               GetToken(Parser);       // Eat the '('
+                               // Read arguments
+                               if( GetToken(Parser) != TOK_PAREN_CLOSE )
+                               {
+                                       PutBack(Parser);
+                                       do {
+                                               AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
+                                       } while(GetToken(Parser) == TOK_COMMA);
+                                       SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
+                               }
+                               
+                       }
+                       // Attribute
+                       else
+                       {
+                               char    name[Parser->TokenLen];
+                               memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
+                               name[Parser->TokenLen-1] = 0;
+                               ret = AST_NewClassElement(Parser, ret, name);
+                       }
+                       continue ;
+               }
+               
+               break ;
        }
+       PutBack(Parser);
        return ret;
 }
 
 /**
- * \brief Get an identifier (constand or function call)
+ * \brief Get an identifier (constant or function call)
  */
-tAST_Node *Parse_GetIdent(tParser *Parser)
+tAST_Node *Parse_GetIdent(tParser *Parser, int bObjectCreate)
 {
-       tAST_Node       *ret;
+       tAST_Node       *ret = NULL;
        char    *name;
        SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
        name = strndup( Parser->TokenStr, Parser->TokenLen );
        
-       #if 0
-       while( GetToken(Parser) == TOK_SCOPE )
+       #if USE_SCOPE_CHAR
+       if( GetToken(Parser) == TOK_SCOPE )
        {
-               ret = AST_New
+               ret = AST_NewScopeDereference( Parser, name, Parse_GetIdent(Parser, bObjectCreate) );
+               free(name);
+               return ret;
        }
        PutBack(Parser);
        #endif
@@ -550,7 +1027,10 @@ tAST_Node *Parse_GetIdent(tParser *Parser)
                printf("Parse_GetIdent: Calling '%s'\n", name);
                #endif
                // Function Call
-               ret = AST_NewFunctionCall( name );
+               if( bObjectCreate )
+                       ret = AST_NewCreateObject( Parser, name );
+               else
+                       ret = AST_NewFunctionCall( Parser, name );
                // Read arguments
                if( GetToken(Parser) != TOK_PAREN_CLOSE )
                {
@@ -567,28 +1047,36 @@ tAST_Node *Parse_GetIdent(tParser *Parser)
                        #endif
                }
        }
-       else {
-               // Runtime Constant
+       else
+       {
+               // Runtime Constant / Variable (When implemented)
                #if DEBUG >= 2
                printf("Parse_GetIdent: Referencing '%s'\n", name);
                #endif
                PutBack(Parser);
-               ret = AST_NewConstant( name );
+               if( bObjectCreate )     // Void constructor (TODO: Should this be an error?)
+                       ret = AST_NewCreateObject( Parser, name );
+               else
+                       ret = AST_NewConstant( Parser, name );
        }
        
        free(name);
        return ret;
 }
 
-/**
- * \brief Check for an error
- */
-void SyntaxAssert(tParser *Parser, int Have, int Want)
+
+void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...)
 {
-       if(Have != Want) {
-               fprintf(stderr, "ERROR: SyntaxAssert Failed, Expected %s(%i), got %s(%i) on line %i\n",
-                       csaTOKEN_NAMES[Want], Want, csaTOKEN_NAMES[Have], Have, Parser->CurLine);
-               longjmp(Parser->JmpTarget, -1);
+       va_list args;
+       va_start(args, Message);
+       fprintf(stderr, "%s:%i: error: ", Parser->Filename, Parser->CurLine);
+       vfprintf(stderr, Message, args);
+       fprintf(stderr, "\n");
+       va_end(args);
+       
+       if( bFatal ) {
+               //longjmp(Parser->JmpTarget, -1);
+               Parser->ErrorHit = 1;
        }
 }
 

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