#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);
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)
/**
* \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);
parser.Filename += sizeof(int); // Move filename
parser.ErrorHit = 0;
- ret = AST_NewScript();
mainCode = AST_NewCodeBlock(&parser);
// Give us an error fallback
{
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!
// 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 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;
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;
}
/**
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);
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)
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;
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: