X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;ds=sidebyside;f=Usermode%2FLibraries%2Flibspiderscript.so_src%2Fparse.c;h=e6d9694227adea7a43606fdef8535a8ae0d89fd2;hb=51121b83f47e7619a7c64d52c8dac5c78b9fd7ee;hp=3e01bb1472dc8254f01eebf0c69309fea559ed32;hpb=55f3607e907b5dd82c5aa61cc289957619cac938;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libspiderscript.so_src/parse.c b/Usermode/Libraries/libspiderscript.so_src/parse.c index 3e01bb14..e6d96942 100644 --- a/Usermode/Libraries/libspiderscript.so_src/parse.c +++ b/Usermode/Libraries/libspiderscript.so_src/parse.c @@ -5,15 +5,19 @@ #include #include #include +#include #include #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,9 +38,19 @@ 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);\ @@ -45,15 +61,13 @@ void SyntaxAssert(tParser *Parser, int Have, int Want); /** * \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); @@ -65,15 +79,31 @@ 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! @@ -86,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); - 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; } /** @@ -173,11 +249,16 @@ tAST_Node *Parse_DoCodeBlock(tParser *Parser) return Parse_DoBlockLine(Parser); } - ret = AST_NewCodeBlock(); + 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; @@ -194,19 +275,54 @@ 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(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); @@ -215,27 +331,105 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) 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: - case TOK_RWD_WHILE: - TODO(Parser, "Implement if, for, do and while\n"); + { + 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); @@ -272,10 +466,27 @@ tAST_Node *Parse_GetVarDef(tParser *Parser, int Type) // 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; } @@ -284,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(Parser, NODETYPE_NOP, ret, Parse_DoExpr0(Parser)); - break; - #if 0 - case TOK_DIV_EQU: - GetToken(Parser); // Eat Token - ret = AST_NewAssign(Parser, NODETYPE_DIVIDE, ret, Parse_DoExpr0(Parser)); - break; - case TOK_MULT_EQU: - GetToken(Parser); // Eat Token - ret = AST_NewAssign(Parser, 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 } /** @@ -317,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(Parser, NODETYPE_LOGICALAND, ret, Parse_DoExpr1(Parser)); - break; - case TOK_LOGICOR: - ret = AST_NewBinOp(Parser, NODETYPE_LOGICALOR, ret, Parse_DoExpr1(Parser)); - break; - case TOK_LOGICXOR: - ret = AST_NewBinOp(Parser, 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 } // -------------------- @@ -342,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(Parser, NODETYPE_EQUALS, ret, Parse_DoExpr2(Parser)); - break; - case TOK_LT: - ret = AST_NewBinOp(Parser, NODETYPE_LESSTHAN, ret, Parse_DoExpr2(Parser)); - break; - case TOK_GT: - ret = AST_NewBinOp(Parser, 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 } /** @@ -368,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(Parser, NODETYPE_BWOR, ret, Parse_DoExpr3(Parser)); - break; - case TOK_AND: - ret = AST_NewBinOp(Parser, NODETYPE_BWAND, ret, Parse_DoExpr3(Parser)); - break; - case TOK_XOR: - ret = AST_NewBinOp(Parser, 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 } // -------------------- @@ -394,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(Parser, NODETYPE_BITSHIFTLEFT, ret, Parse_DoExpr5(Parser)); - break; - case TOK_SHR: - ret = AST_NewBinOp(Parser, 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 } // -------------------- @@ -417,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(Parser, NODETYPE_ADD, ret, Parse_DoExpr5(Parser)); - break; - case TOK_MINUS: - ret = AST_NewBinOp(Parser, 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 } // -------------------- @@ -440,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(Parser, NODETYPE_MULTIPLY, ret, Parse_DoExpr6(Parser)); + case TOK_INCREMENT: + ret = AST_NewUniOp(Parser, NODETYPE_POSTINC, ret); break; - case TOK_DIV: - ret = AST_NewBinOp(Parser, 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 @@ -506,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", @@ -562,8 +892,8 @@ tAST_Node *Parse_GetString(tParser *Parser) tAST_Node *Parse_GetNumeric(tParser *Parser) { uint64_t value = 0; - char *pos; - GetToken( Parser ); + const char *pos; + SyntaxAssert( Parser, GetToken( Parser ), TOK_INTEGER ); pos = Parser->TokenStr; //printf("pos = %p, *pos = %c\n", pos, *pos); @@ -623,30 +953,70 @@ tAST_Node *Parse_GetVariable(tParser *Parser) printf("Parse_GetVariable: name = '%s'\n", name); #endif } - // Handle array references - while( LookAhead(Parser) == TOK_SQUARE_OPEN ) + for(;;) { GetToken(Parser); - ret = AST_NewBinOp(Parser, 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 @@ -657,7 +1027,10 @@ tAST_Node *Parse_GetIdent(tParser *Parser) printf("Parse_GetIdent: Calling '%s'\n", name); #endif // Function Call - ret = AST_NewFunctionCall( Parser, name ); + if( bObjectCreate ) + ret = AST_NewCreateObject( Parser, name ); + else + ret = AST_NewFunctionCall( Parser, name ); // Read arguments if( GetToken(Parser) != TOK_PAREN_CLOSE ) { @@ -674,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( Parser, 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; } }