X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibspiderscript.so_src%2Fparse.c;h=e6d9694227adea7a43606fdef8535a8ae0d89fd2;hb=239f2374299c1471a40b1087725b32f3f163d9b3;hp=2ccf5d8738c5d2b8120bbd053be363c8f65ca752;hpb=efa38e0d56b1b620b6f4e5c4f91abc483a3065e2;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libspiderscript.so_src/parse.c b/Usermode/Libraries/libspiderscript.so_src/parse.c index 2ccf5d87..e6d96942 100644 --- a/Usermode/Libraries/libspiderscript.so_src/parse.c +++ b/Usermode/Libraries/libspiderscript.so_src/parse.c @@ -5,14 +5,22 @@ #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_DoExpr(tParser *Parser); +tAST_Node *Parse_DoBlockLine(tParser *Parser); +tAST_Node *Parse_GetVarDef(tParser *Parser, int Type); tAST_Node *Parse_DoExpr0(tParser *Parser); // Assignment tAST_Node *Parse_DoExpr1(tParser *Parser); // Boolean Operators @@ -21,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 @@ -28,59 +38,202 @@ 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) -void SyntaxAssert(int Have, int Want); +#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); + #endif // Initialise parser + parser.LastToken = -1; + parser.NextToken = -1; + 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); - for(;;) + // Give us an error fallback + if( setjmp( parser.JmpTarget ) != 0 ) + { + AST_FreeNode( mainCode ); + + 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) ) { - case TOK_RWD_FUNCTION: - // Define a function - SyntaxAssert( GetToken(Parser), TOK_IDENT ); - name = strndup( Parser->TokenStr, Parser->TokenLen ); - fcn = AST_AppendFunction( ret, name ); - free(name); + case TOK_EOF: + break; + + // Typed variables/functions + case TOKEN_GROUP_TYPES: + TOKEN_GET_DATATYPE(type, Parser->Token); - SyntaxAssert( GetToken(Parser), TOK_PAREN_OPEN ); - // TODO: Arguments - SyntaxAssert( GetToken(Parser), TOK_PAREN_CLOSE ); + switch(GetToken(Parser)) + { + // Define a function (pass on to the other function definition code) + case TOK_IDENT: + PutBack(Parser); + if( Parse_FunctionDefinition(Script, Parser, type) == NULL ) + longjmp(Parser->JmpTarget, -1); + break ; + // Define a variable + 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( !Script->Variant->bDyamicTyped ) { + SyntaxError(Parser, 1, "Dynamic functions are invalid in static mode"); + longjmp(Parser->JmpTarget, -1); + } - 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_DoExpr(Parser) ); + PutBack(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 ); - return ret; + //printf("---- %p parsed as SpiderScript ----\n", Buffer); + + 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; } /** @@ -89,24 +242,252 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer) tAST_Node *Parse_DoCodeBlock(tParser *Parser) { tAST_Node *ret; - SyntaxAssert( 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 ) + { + tAST_Node *node = Parse_DoBlockLine(Parser); + if(!node) { + AST_FreeNode(ret); + return NULL; + } + AST_AppendNode( ret, node ); + } + GetToken(Parser); // Omnomnom + return ret; +} + +/** + * \brief Parse a line in a block + */ +tAST_Node *Parse_DoBlockLine(tParser *Parser) +{ + tAST_Node *ret; + + //printf("Parse_DoBlockLine: Line %i\n", Parser->CurLine); - while( GetToken(Parser) != TOK_BRACE_CLOSE ) + switch(LookAhead(Parser)) { - AST_AppendNode( ret, Parse_DoExpr(Parser) ); - SyntaxAssert( GetToken(Parser), TOK_SEMICOLON ); + // 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: + 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); + 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; + GetToken(Parser); + TOKEN_GET_DATATYPE(type, Parser->Token); + + SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE); + + ret = Parse_GetVarDef(Parser, type); + } + break; + + // Default + default: + //printf("exp0\n"); + ret = Parse_DoExpr0(Parser); + break; } + + SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON ); return ret; } /** - * \brief Parse an expression + * \brief Get a variable definition */ -tAST_Node *Parse_DoExpr(tParser *Parser) +tAST_Node *Parse_GetVarDef(tParser *Parser, int Type) { - return Parse_DoExpr0(Parser); + char name[Parser->TokenLen]; + tAST_Node *ret; + + SyntaxAssert(Parser, Parser->Token, TOK_VARIABLE); + + // copy the name (trimming the $) + memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1); + name[Parser->TokenLen-1] = 0; + // Define the variable + ret = AST_NewDefineVar(Parser, Type, name); + // Handle arrays + while( LookAhead(Parser) == TOK_SQUARE_OPEN ) + { + tAST_Node *node; + GetToken(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; } /** @@ -114,28 +495,41 @@ tAST_Node *Parse_DoExpr(tParser *Parser) */ 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_NewAssignOp(ret, NODETYPE_DIVIDE, DoExpr0(Parser)); - break; - case TOK_MULT_EQU: - GetToken(Parser); // Eat Token - ret = AST_NewAssignOp(ret, NODETYPE_MULTIPLY, DoExpr0(Parser)); - break; - #endif - default: 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 } /** @@ -143,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 } // -------------------- @@ -168,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 } /** @@ -194,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 } // -------------------- @@ -220,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 } // -------------------- @@ -243,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 } // -------------------- @@ -266,36 +704,104 @@ 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 // -------------------- tAST_Node *Parse_DoParen(tParser *Parser) { + #if DEBUG >= 2 + printf("Parse_DoParen: (Parser=%p)\n", Parser); + #endif if(LookAhead(Parser) == TOK_PAREN_OPEN) { tAST_Node *ret; + int type; GetToken(Parser); - ret = Parse_DoExpr0(Parser); - SyntaxAssert(GetToken(Parser), TOK_PAREN_CLOSE); + + // TODO: Handle casts here + 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 @@ -309,16 +815,36 @@ tAST_Node *Parse_DoValue(tParser *Parser) { int tok = LookAhead(Parser); + #if DEBUG >= 2 + printf("Parse_DoValue: tok = %i\n", tok); + #endif + 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: - //ParseError2( tok, TOK_T_VALUE ); - return NULL; + fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n", + csaTOKEN_NAMES[tok], Parser->CurLine); + longjmp( Parser->JmpTarget, -1 ); } } @@ -328,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; } @@ -339,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 ); } /** @@ -350,58 +942,141 @@ tAST_Node *Parse_GetNumeric(tParser *Parser) */ tAST_Node *Parse_GetVariable(tParser *Parser) { - char *name; tAST_Node *ret; - SyntaxAssert( GetToken(Parser), TOK_VARIABLE ); - name = strndup( Parser->TokenStr+1, Parser->TokenLen-1 ); - ret = AST_NewVariable( name ); - free(name); + SyntaxAssert( Parser, GetToken(Parser), TOK_VARIABLE ); + { + char name[Parser->TokenLen]; + memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1); + name[Parser->TokenLen-1] = 0; + ret = AST_NewVariable( Parser, name ); + #if DEBUG >= 2 + printf("Parse_GetVariable: name = '%s'\n", name); + #endif + } + for(;;) + { + GetToken(Parser); + 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( GetToken(Parser), TOK_IDENT ); + SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT ); name = strndup( Parser->TokenStr, Parser->TokenLen ); + #if USE_SCOPE_CHAR + if( GetToken(Parser) == TOK_SCOPE ) + { + ret = AST_NewScopeDereference( Parser, name, Parse_GetIdent(Parser, bObjectCreate) ); + free(name); + return ret; + } + PutBack(Parser); + #endif + if( GetToken(Parser) == TOK_PAREN_OPEN ) { + #if DEBUG >= 2 + 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 ) { PutBack(Parser); do { + #if DEBUG >= 2 + printf(" Parse_GetIdent: Argument\n"); + #endif AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) ); } while(GetToken(Parser) == TOK_COMMA); - SyntaxAssert( Parser->Token, TOK_PAREN_CLOSE ); + SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE ); + #if DEBUG >= 2 + printf(" Parse_GetIdent: All arguments parsed\n"); + #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(int Have, int Want) + +void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...) { - if(Have != Want) { - fprintf(stderr, "ERROR: Expected %i, got %i\n", Want, Have); - //longjmp(jmpTarget, 1); - return; + 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; } }