X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibspiderscript.so_src%2Fparse.c;h=45eafb2b87f3aaab93390af7935fde851f31cd20;hb=da93bf59c8d6d7cd4a5547f444197abf0490d399;hp=12f26747112116222dc675953c6398f491ff1ebf;hpb=3bf0a5e914ee87da14a3255ad4b706994d54f0d6;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libspiderscript.so_src/parse.c b/Usermode/Libraries/libspiderscript.so_src/parse.c index 12f26747..45eafb2b 100644 --- a/Usermode/Libraries/libspiderscript.so_src/parse.c +++ b/Usermode/Libraries/libspiderscript.so_src/parse.c @@ -10,14 +10,17 @@ #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); -tAST_Node *Parse_DoCodeBlock(tParser *Parser); -tAST_Node *Parse_DoBlockLine(tParser *Parser); + 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 *CodeNode); +tAST_Node *Parse_DoBlockLine(tParser *Parser, tAST_Node *CodeNode); +tAST_Node *Parse_VarDefList(tParser *Parser, tAST_Node *CodeNode, int Type); tAST_Node *Parse_GetVarDef(tParser *Parser, int Type); tAST_Node *Parse_DoExpr0(tParser *Parser); // Assignment @@ -41,13 +44,17 @@ 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 { \ - if( (_have) != (_want) ) { \ +#if 0 +#define SyntaxAssert(_parser, _have, _want) SyntaxAssertV(_parser, _have, _want, NULL) +#define SyntaxAssertV(_parser, _have, _want, _rv) 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; \ + csaTOKEN_NAMES[have], have, csaTOKEN_NAMES[want], want); \ + return _rv; \ } \ }while(0) +#endif #define TODO(Parser, message...) do {\ fprintf(stderr, "TODO: "message);\ @@ -58,14 +65,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); @@ -83,8 +89,8 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const cha *(int*)(parser.Filename) = 0; // Set reference count parser.Filename += sizeof(int); // Move filename parser.ErrorHit = 0; + parser.Variant = Script->Variant; - ret = AST_NewScript(); mainCode = AST_NewCodeBlock(&parser); // Give us an error fallback @@ -92,24 +98,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! @@ -124,26 +123,18 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const cha case TOKEN_GROUP_TYPES: TOKEN_GET_DATATYPE(type, Parser->Token); - switch(GetToken(Parser)) + switch(LookAhead(Parser)) { // 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 + // Define a variable (pass back to _DoBlockLine) 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); - } + node = Parse_VarDefList(Parser, mainCode, type); + AST_AppendNode(mainCode, node); + SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON); break; default: SyntaxError(Parser, 1, "Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n", @@ -154,14 +145,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; @@ -169,7 +160,7 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const cha // Ordinary Statement default: PutBack(Parser); - node = Parse_DoBlockLine(Parser); + node = Parse_DoBlockLine(Parser, mainCode); if(!node) longjmp(Parser->JmpTarget, -1); AST_AppendNode( mainCode, node ); break; @@ -180,71 +171,86 @@ 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, NULL); + + 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; } /** * \brief Parse a block of code surrounded by { } */ -tAST_Node *Parse_DoCodeBlock(tParser *Parser) +tAST_Node *Parse_DoCodeBlock(tParser *Parser, tAST_Node *CodeNode) { tAST_Node *ret; // Check if we are being called for a one-liner if( GetToken(Parser) != TOK_BRACE_OPEN ) { PutBack(Parser); - return Parse_DoBlockLine(Parser); + return Parse_DoBlockLine(Parser, CodeNode); } ret = AST_NewCodeBlock(Parser); while( LookAhead(Parser) != TOK_BRACE_CLOSE ) { - tAST_Node *node = Parse_DoBlockLine(Parser); + tAST_Node *node = Parse_DoBlockLine(Parser, ret); if(!node) { AST_FreeNode(ret); return NULL; @@ -258,7 +264,7 @@ tAST_Node *Parse_DoCodeBlock(tParser *Parser) /** * \brief Parse a line in a block */ -tAST_Node *Parse_DoBlockLine(tParser *Parser) +tAST_Node *Parse_DoBlockLine(tParser *Parser, tAST_Node *CodeNode) { tAST_Node *ret; @@ -268,7 +274,7 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) { // New block case TOK_BRACE_OPEN: - return Parse_DoCodeBlock(Parser); + return Parse_DoCodeBlock(Parser, CodeNode); // Empty statement case TOK_SEMICOLON: @@ -281,18 +287,46 @@ 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); - true = Parse_DoCodeBlock(Parser); + true = Parse_DoCodeBlock(Parser, CodeNode); if( LookAhead(Parser) == TOK_RWD_ELSE ) { GetToken(Parser); - false = Parse_DoCodeBlock(Parser); + false = Parse_DoCodeBlock(Parser, CodeNode); } else false = AST_NewNop(Parser); @@ -302,8 +336,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) @@ -321,32 +367,57 @@ 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); + code = Parse_DoCodeBlock(Parser, CodeNode); + 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' - code = Parse_DoCodeBlock(Parser); + + #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, CodeNode); 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); + code = Parse_DoCodeBlock(Parser, CodeNode); + ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 0, cond, AST_NewNop(Parser), code); } return ret; @@ -356,10 +427,7 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) int type; GetToken(Parser); TOKEN_GET_DATATYPE(type, Parser->Token); - - SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE); - - ret = Parse_GetVarDef(Parser, type); + ret = Parse_VarDefList(Parser, CodeNode, type); } break; @@ -374,6 +442,23 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) return ret; } +tAST_Node *Parse_VarDefList(tParser *Parser, tAST_Node *CodeNode, int Type) +{ + tAST_Node *ret; + + ret = NULL; + do { + if(ret) AST_AppendNode( CodeNode, ret ); + SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE); + + ret = Parse_GetVarDef(Parser, Type); + if(!ret) longjmp(Parser->JmpTarget, -1); + } while(GetToken(Parser) == TOK_COMMA); + PutBack(Parser); // Semicolon is checked by caller + + return ret; +} + /** * \brief Get a variable definition */ @@ -381,30 +466,52 @@ tAST_Node *Parse_GetVarDef(tParser *Parser, int Type) { char name[Parser->TokenLen]; tAST_Node *ret; + int level; 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 ) + level = 0; + if( LookAhead(Parser) == TOK_SQUARE_OPEN ) { - tAST_Node *node; GetToken(Parser); - node = Parse_DoExpr0(Parser); - if(!node) { - AST_FreeNode(ret); - return NULL; + if( LookAhead(Parser) != TOK_SQUARE_CLOSE ) + { + ret->DefVar.InitialValue = AST_NewFunctionCall(Parser, "array"); + AST_AppendFunctionCallArg(ret->DefVar.InitialValue, Parse_DoExpr0(Parser)); } - AST_AppendNode(ret, node); SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE); + + level ++; + } + while( LookAhead(Parser) == TOK_SQUARE_OPEN ) + { + GetToken(Parser); + SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE); + level ++; } + // Maul the type to denote the dereference level + if( Parser->Variant->bDyamicTyped ) { + ret->DefVar.DataType = SS_DATATYPE_ARRAY; + } + else { + ret->DefVar.DataType |= (level << 16); + } + + // Initial value if( LookAhead(Parser) == TOK_ASSIGN ) { + if( ret->DefVar.InitialValue ) + { + SyntaxError(Parser, 1, "Cannot assign and set array size at the same time"); + } GetToken(Parser); ret->DefVar.InitialValue = Parse_DoExpr0(Parser); if(!ret->DefVar.InitialValue) { @@ -412,6 +519,10 @@ tAST_Node *Parse_GetVarDef(tParser *Parser, int Type) return NULL; } } + else if( ret->DefVar.InitialValue ) + { + AST_AppendFunctionCallArg(ret->DefVar.InitialValue, AST_NewInteger(Parser, ret->DefVar.DataType)); + } return ret; } @@ -507,6 +618,9 @@ tAST_Node *Parse_DoExpr2(tParser *Parser) case TOK_EQUALS: ret = AST_NewBinOp(Parser, NODETYPE_EQUALS, ret, _next(Parser)); break; + case TOK_NOTEQUALS: + ret = AST_NewBinOp(Parser, NODETYPE_NOTEQUALS, ret, _next(Parser)); + break; case TOK_LT: ret = AST_NewBinOp(Parser, NODETYPE_LESSTHAN, ret, _next(Parser)); break; @@ -756,10 +870,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_NewNull(Parser); // nODETYPE_NOP returns NULL case TOK_RWD_NEW: - GetToken(Parser); // Omnomnom + GetToken(Parser); return Parse_GetIdent(Parser, 1); default: @@ -1001,3 +1120,11 @@ void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...) } } +void SyntaxAssert(tParser *Parser, int Have, int Want) +{ + if( Have != Want ) + { + SyntaxError(Parser, 1, "Unexpected %s(%i), expecting %s(%i)\n", + csaTOKEN_NAMES[Have], Have, csaTOKEN_NAMES[Want], Want); + } +}