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