X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibspiderscript.so_src%2Fparse.c;h=b25dd21246e85748ba4cf771ed971a6fb5018cf7;hb=ec6f426069129f0a3d207f743ecddceddb57db8e;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..b25dd212 100644 --- a/Usermode/Libraries/libspiderscript.so_src/parse.c +++ b/Usermode/Libraries/libspiderscript.so_src/parse.c @@ -6,13 +6,17 @@ #include #include #include +#define WANT_TOKEN_STRINGS 1 #include "tokens.h" #include "ast.h" +#define DEBUG 0 + // === PROTOTYPES === tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer); 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 @@ -30,7 +34,12 @@ tAST_Node *Parse_GetNumeric(tParser *Parser); tAST_Node *Parse_GetVariable(tParser *Parser); tAST_Node *Parse_GetIdent(tParser *Parser); -void SyntaxAssert(int Have, int Want); +void SyntaxAssert(tParser *Parser, int Have, int Want); + +#define TODO(Parser, message...) do {\ + fprintf(stderr, "TODO: "message);\ + longjmp(Parser->JmpTarget, -1);\ +}while(0) // === CODE === /** @@ -44,35 +53,101 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer) tAST_Node *mainCode; char *name; tAST_Function *fcn; + int type; + + #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; ret = AST_NewScript(); mainCode = AST_NewCodeBlock(); - for(;;) + // Give us an error fallback + if( setjmp( parser.JmpTarget ) != 0 ) + { + AST_FreeNode( mainCode ); + return NULL; + } + + // Parse the file! + while(Parser->Token != TOK_EOF) { switch( GetToken(Parser) ) { - case TOK_RWD_FUNCTION: - // Define a function - SyntaxAssert( GetToken(Parser), TOK_IDENT ); + case TOK_EOF: + break; + + // Typed variables/functions + case TOKEN_GROUP_TYPES: + { + int tok, type; + TOKEN_GET_DATATYPE(type, Parser->Token); + + tok = GetToken(Parser); + // Define a function (pass on to the other function definition code) + if( tok == TOK_IDENT ) { + goto defFcn; + } + // 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]); + } + } + break; + + // Define a function + case TOK_RWD_FUNCTION: + if( !Variant->bDyamicTyped ) { + fprintf(stderr, "ERROR: Attempt to create a dynamic function\n"); + 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); - SyntaxAssert( GetToken(Parser), TOK_PAREN_OPEN ); - // TODO: Arguments - SyntaxAssert( GetToken(Parser), TOK_PAREN_CLOSE ); + // 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) ); break; default: - PutBack(&parser); - AST_AppendNode( mainCode, Parse_DoExpr(Parser) ); + PutBack(Parser); + AST_AppendNode( mainCode, Parse_DoBlockLine(Parser) ); break; } } @@ -80,6 +155,8 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer) fcn = AST_AppendFunction( ret, "" ); AST_SetFunctionCode( fcn, mainCode ); + printf("---- %p parsed as SpiderScript ----\n", Buffer); + return ret; } @@ -89,24 +166,117 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer) tAST_Node *Parse_DoCodeBlock(tParser *Parser) { tAST_Node *ret; - SyntaxAssert( GetToken(Parser), TOK_BRACE_OPEN ); + + // 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(); - while( GetToken(Parser) != TOK_BRACE_CLOSE ) + while( LookAhead(Parser) != TOK_BRACE_CLOSE ) { - AST_AppendNode( ret, Parse_DoExpr(Parser) ); - SyntaxAssert( GetToken(Parser), TOK_SEMICOLON ); + AST_AppendNode( ret, Parse_DoBlockLine(Parser) ); + } + 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); + + switch(LookAhead(Parser)) + { + + // Return from a method + case TOK_RWD_RETURN: + //printf("return\n"); + GetToken(Parser); + ret = AST_NewUniOp(NODETYPE_RETURN, Parse_DoExpr0(Parser)); + 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); + } + ret = AST_NewIf(cond, true, false); + } + return ret; + case TOK_RWD_FOR: + case TOK_RWD_DO: + case TOK_RWD_WHILE: + TODO(Parser, "Implement if, for, do and while\n"); + break; + + // 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; + } + + 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(Type, name); + // Handle arrays + while( LookAhead(Parser) == TOK_SQUARE_OPEN ) + { + GetToken(Parser); + AST_AppendNode(ret, Parse_DoExpr0(Parser)); + SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE); + } + return ret; } /** @@ -126,14 +296,18 @@ tAST_Node *Parse_DoExpr0(tParser *Parser) #if 0 case TOK_DIV_EQU: GetToken(Parser); // Eat Token - ret = AST_NewAssignOp(ret, NODETYPE_DIVIDE, DoExpr0(Parser)); + ret = AST_NewAssign(NODETYPE_DIVIDE, ret, Parse_DoExpr0(Parser)); break; case TOK_MULT_EQU: GetToken(Parser); // Eat Token - ret = AST_NewAssignOp(ret, NODETYPE_MULTIPLY, DoExpr0(Parser)); + ret = AST_NewAssign(NODETYPE_MULTIPLY, ret, Parse_DoExpr0(Parser)); break; #endif - default: break; + default: + #if DEBUG >= 2 + printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token); + #endif + break; } return ret; } @@ -290,12 +464,18 @@ tAST_Node *Parse_DoExpr6(tParser *Parser) // -------------------- 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; GetToken(Parser); + + // TODO: Handle casts here + ret = Parse_DoExpr0(Parser); - SyntaxAssert(GetToken(Parser), TOK_PAREN_CLOSE); + SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE); return ret; } else @@ -309,6 +489,10 @@ 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); @@ -317,8 +501,9 @@ tAST_Node *Parse_DoValue(tParser *Parser) case TOK_VARIABLE: return Parse_GetVariable(Parser); 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 ); } } @@ -350,12 +535,24 @@ 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( name ); + #if DEBUG >= 2 + printf("Parse_GetVariable: name = '%s'\n", name); + #endif + } + // Handle array references + while( LookAhead(Parser) == TOK_SQUARE_OPEN ) + { + GetToken(Parser); + ret = AST_NewBinOp(NODETYPE_INDEX, ret, Parse_DoExpr0(Parser)); + SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE); + } return ret; } @@ -366,11 +563,22 @@ tAST_Node *Parse_GetIdent(tParser *Parser) { tAST_Node *ret; char *name; - SyntaxAssert( GetToken(Parser), TOK_IDENT ); + SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT ); name = strndup( Parser->TokenStr, Parser->TokenLen ); + #if 0 + while( GetToken(Parser) == TOK_SCOPE ) + { + ret = AST_New + } + 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 ); // Read arguments @@ -378,13 +586,22 @@ tAST_Node *Parse_GetIdent(tParser *Parser) { 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 + #if DEBUG >= 2 + printf("Parse_GetIdent: Referencing '%s'\n", name); + #endif PutBack(Parser); ret = AST_NewConstant( name ); } @@ -396,12 +613,12 @@ tAST_Node *Parse_GetIdent(tParser *Parser) /** * \brief Check for an error */ -void SyntaxAssert(int Have, int Want) +void SyntaxAssert(tParser *Parser, int Have, int Want) { if(Have != Want) { - fprintf(stderr, "ERROR: Expected %i, got %i\n", Want, Have); - //longjmp(jmpTarget, 1); - return; + 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); } }