/* include one of a number of predefined libraries, or perhaps an actual file */ void IncludeFile(char *FileName) { struct IncludeLibrary *LInclude; /* scan for the include file name to see if it's in our list of predefined includes */ for (LInclude = IncludeLibList; LInclude != NULL; LInclude = LInclude->NextLib) { if (strcmp(LInclude->IncludeName, FileName) == 0) { /* found it - protect against multiple inclusion */ if (!VariableDefined(FileName)) { VariableDefine(NULL, FileName, NULL, &VoidType, FALSE); /* run an extra startup function if there is one */ if (LInclude->SetupFunction != NULL) (*LInclude->SetupFunction)(); /* parse the setup C source code - may define types etc. */ if (LInclude->SetupCSource != NULL) PicocParse(FileName, LInclude->SetupCSource, strlen(LInclude->SetupCSource), TRUE, TRUE, FALSE); /* set up the library functions */ if (LInclude->FuncList != NULL) LibraryAdd(&GlobalTable, FileName, LInclude->FuncList); } return; } } /* not a predefined file, read a real file */ PicocPlatformScanFile(FileName); }
/* creates various system-dependent definitions */ void UnistdSetupFunc(void) { /* define NULL */ if (!VariableDefined(TableStrRegister("NULL"))) VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); /* define optarg and friends */ VariableDefinePlatformVar(NULL, "optarg", CharPtrType, (union AnyValue *)&optarg, TRUE); VariableDefinePlatformVar(NULL, "optind", &IntType, (union AnyValue *)&optind, TRUE); VariableDefinePlatformVar(NULL, "opterr", &IntType, (union AnyValue *)&opterr, TRUE); VariableDefinePlatformVar(NULL, "optopt", &IntType, (union AnyValue *)&optopt, TRUE); }
/* creates various system-dependent definitions */ void StdioSetupFunc(void) { struct LibraryFunction *plib; plib = &StdioFunctions; plib[ 0].Func = StdioSprintf ; plib[ 1].Func = StdioPuts ; plib[ 2].Func = StdioGets ; plib[ 3].Func = StdioCls ; plib[ 4].Func = StdioFopen ; plib[ 5].Func = StdioFreopen ; plib[ 6].Func = StdioFclose ; plib[ 7].Func = StdioFread ; plib[ 8].Func = StdioFwrite ; plib[ 9].Func = StdioFgetc ; plib[10].Func = StdioFgetc ; plib[11].Func = StdioFgets ; plib[12].Func = StdioFputc ; plib[13].Func = StdioFputs ; plib[14].Func = StdioFeof ; plib[15].Func = StdioFtell ; plib[16].Func = StdioFseek ; plib[17].Func = StdioPrintf ; struct ValueType *StructFileType; struct ValueType *FilePtrType; /* make a "struct __FILEStruct" which is the same size as a native FILE structure */ StructFileType = TypeCreateOpaqueStruct(NULL, TableStrRegister("__FILEStruct"), sizeof(FILE)); /* get a FILE * type */ FilePtrType = TypeGetMatching(NULL, StructFileType, TypePointer, 0, StrEmpty, TRUE); /* make a "struct __va_listStruct" which is the same size as our struct StdVararg */ TypeCreateOpaqueStruct(NULL, TableStrRegister("__va_listStruct"), sizeof(FILE)); /* define EOF equal to the system EOF */ VariableDefinePlatformVar(NULL, "EOF", &IntType, (union AnyValue *)&EOFValue, FALSE); VariableDefinePlatformVar(NULL, "SEEK_SET", &IntType, (union AnyValue *)&SEEK_SETValue, FALSE); VariableDefinePlatformVar(NULL, "SEEK_CUR", &IntType, (union AnyValue *)&SEEK_CURValue, FALSE); VariableDefinePlatformVar(NULL, "SEEK_END", &IntType, (union AnyValue *)&SEEK_ENDValue, FALSE); VariableDefinePlatformVar(NULL, "BUFSIZ", &IntType, (union AnyValue *)&BUFSIZValue, FALSE); VariableDefinePlatformVar(NULL, "FILENAME_MAX", &IntType, (union AnyValue *)&FILENAME_MAXValue, FALSE); /* define NULL*/ if (!VariableDefined(TableStrRegister("NULL"))) VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); }
/* include one of a number of predefined libraries, or perhaps an actual file */ void IncludeFile(Picoc *pc, char *FileName) { struct IncludeLibrary *LInclude; struct InteractiveState_Struct OldState; /* scan for the include file name to see if it's in our list of predefined includes */ for (LInclude = pc->IncludeLibList; LInclude != NULL; LInclude = LInclude->NextLib) { if (strcmp(LInclude->IncludeName, FileName) == 0) { /* found it - protect against multiple inclusion */ if (!VariableDefined(pc, FileName)) { VariableDefine(pc, NULL, FileName, NULL, &pc->VoidType, FALSE); /* run an extra startup function if there is one */ if (LInclude->SetupFunction != NULL) (*LInclude->SetupFunction)(pc); /* parse the setup C source code - may define types etc. */ if (LInclude->SetupCSource != NULL) PicocParse(pc, FileName, LInclude->SetupCSource, (int) strlen(LInclude->SetupCSource), TRUE, TRUE, FALSE, FALSE); /* set up the library functions */ if (LInclude->FuncList != NULL) LibraryAdd(pc, &pc->GlobalTable, FileName, LInclude->FuncList); } return; } } /* not a predefined file, read a real file */ OldState = pc->InteractiveState; memset(&pc->InteractiveState, 0, sizeof(pc->InteractiveState)); PicocPlatformScanFile(pc, FileName); pc->InteractiveState = OldState; }
/** * creates various system-dependent definitions * * We retain values like stdout, stdin and stderr in this * function to avoid having to invent "FilePtrType" for * rotables. */ void StdioSetupFunc(void) { struct ValueType *StructFileType; struct ValueType *FilePtrType; /* make a "struct __FILEStruct" which is the same size as a native FILE structure */ StructFileType = TypeCreateOpaqueStruct(NULL, TableStrRegister("__FILEStruct"), sizeof(FILE)); /* get a FILE * type */ FilePtrType = TypeGetMatching(NULL, StructFileType, TypePointer, 0, StrEmpty, TRUE); /* make a "struct __va_listStruct" which is the same size as our struct StdVararg */ TypeCreateOpaqueStruct(NULL, TableStrRegister("__va_listStruct"), sizeof(FILE)); /* define stdin, stdout and stderr */ VariableDefinePlatformVar(NULL, "stdin", FilePtrType, (union AnyValue *)&stdinValue, FALSE); VariableDefinePlatformVar(NULL, "stdout", FilePtrType, (union AnyValue *)&stdoutValue, FALSE); VariableDefinePlatformVar(NULL, "stderr", FilePtrType, (union AnyValue *)&stderrValue, FALSE); /* define NULL, TRUE and FALSE */ if (!VariableDefined(TableStrRegister("NULL"))) VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); }
void PicocCallMain(int argc, char **argv) { /* check if the program wants arguments */ struct Value *FuncValue = NULL; if (!VariableDefined(TableStrRegister("main"))) ProgramFail(NULL, "main() no esta definido"); VariableGet(NULL, TableStrRegister("main"), &FuncValue); if (FuncValue->Typ->Base != TypeFunction) ProgramFail(NULL, "main no es una funcion - no puedo llamarla"); if (FuncValue->Val->FuncDef.NumParams != 0) { /* define the arguments */ VariableDefinePlatformVar(NULL, "__argc", &IntType, (union AnyValue *)&argc, FALSE); VariableDefinePlatformVar(NULL, "__argv", CharPtrPtrType, (union AnyValue *)&argv, FALSE); } if (FuncValue->Val->FuncDef.ReturnType == &VoidType) { if (FuncValue->Val->FuncDef.NumParams == 0) PicocParse("startup", CALL_MAIN_NO_ARGS_RETURN_VOID, strlen(CALL_MAIN_NO_ARGS_RETURN_VOID), TRUE, TRUE, FALSE); else PicocParse("startup", CALL_MAIN_WITH_ARGS_RETURN_VOID, strlen(CALL_MAIN_WITH_ARGS_RETURN_VOID), TRUE, TRUE, FALSE); } else { VariableDefinePlatformVar(NULL, "__exit_value", &IntType, (union AnyValue *)&PicocExitValue, TRUE); if (FuncValue->Val->FuncDef.NumParams == 0) PicocParse("startup", CALL_MAIN_NO_ARGS_RETURN_INT, strlen(CALL_MAIN_NO_ARGS_RETURN_INT), TRUE, TRUE, FALSE); else PicocParse("startup", CALL_MAIN_WITH_ARGS_RETURN_INT, strlen(CALL_MAIN_WITH_ARGS_RETURN_INT), TRUE, TRUE, FALSE); } }
void PicocCallMain(Picoc *pc, int argc, char **argv) { /* check if the program wants arguments */ struct Value *FuncValue = NULL; if (!VariableDefined(pc, TableStrRegister(pc, "main"))) ProgramFailNoParser(pc, "main() is not defined"); VariableGet(pc, NULL, TableStrRegister(pc, "main"), &FuncValue); if (FuncValue->Typ->Base != TypeFunction) ProgramFailNoParser(pc, "main is not a function - can't call it"); if (FuncValue->Val->FuncDef.NumParams != 0) { /* define the arguments */ VariableDefinePlatformVar(pc, NULL, "__argc", &pc->IntType, (union AnyValue *)&argc, FALSE); VariableDefinePlatformVar(pc, NULL, "__argv", pc->CharPtrPtrType, (union AnyValue *)&argv, FALSE); } if (FuncValue->Val->FuncDef.ReturnType == &pc->VoidType) { if (FuncValue->Val->FuncDef.NumParams == 0) PicocParse(pc, "startup", CALL_MAIN_NO_ARGS_RETURN_VOID, strlen(CALL_MAIN_NO_ARGS_RETURN_VOID), TRUE, TRUE, FALSE, TRUE); else PicocParse(pc, "startup", CALL_MAIN_WITH_ARGS_RETURN_VOID, strlen(CALL_MAIN_WITH_ARGS_RETURN_VOID), TRUE, TRUE, FALSE, TRUE); } else { VariableDefinePlatformVar(pc, NULL, "__exit_value", &pc->IntType, (union AnyValue *)&pc->PicocExitValue, TRUE); if (FuncValue->Val->FuncDef.NumParams == 0) PicocParse(pc, "startup", CALL_MAIN_NO_ARGS_RETURN_INT, strlen(CALL_MAIN_NO_ARGS_RETURN_INT), TRUE, TRUE, FALSE, TRUE); else PicocParse(pc, "startup", CALL_MAIN_WITH_ARGS_RETURN_INT, strlen(CALL_MAIN_WITH_ARGS_RETURN_INT), TRUE, TRUE, FALSE, TRUE); } }
/* creates various system-dependent definitions */ void StdioSetupFunc(Picoc *pc) { struct ValueType *StructFileType; struct ValueType *FilePtrType; /* make a "struct __FILEStruct" which is the same size as a native FILE structure */ StructFileType = TypeCreateOpaqueStruct(pc, NULL, TableStrRegister(pc, "__FILEStruct"), sizeof(FILE)); /* get a FILE * type */ FilePtrType = TypeGetMatching(pc, NULL, StructFileType, TypePointer, 0, pc->StrEmpty, TRUE); /* make a "struct __va_listStruct" which is the same size as our struct StdVararg */ TypeCreateOpaqueStruct(pc, NULL, TableStrRegister(pc, "__va_listStruct"), sizeof(FILE)); /* define EOF equal to the system EOF */ VariableDefinePlatformVar(pc, NULL, "EOF", &pc->IntType, (union AnyValue *)&EOFValue, FALSE); VariableDefinePlatformVar(pc, NULL, "SEEK_SET", &pc->IntType, (union AnyValue *)&SEEK_SETValue, FALSE); VariableDefinePlatformVar(pc, NULL, "SEEK_CUR", &pc->IntType, (union AnyValue *)&SEEK_CURValue, FALSE); VariableDefinePlatformVar(pc, NULL, "SEEK_END", &pc->IntType, (union AnyValue *)&SEEK_ENDValue, FALSE); VariableDefinePlatformVar(pc, NULL, "BUFSIZ", &pc->IntType, (union AnyValue *)&BUFSIZValue, FALSE); VariableDefinePlatformVar(pc, NULL, "FILENAME_MAX", &pc->IntType, (union AnyValue *)&FILENAME_MAXValue, FALSE); VariableDefinePlatformVar(pc, NULL, "_IOFBF", &pc->IntType, (union AnyValue *)&_IOFBFValue, FALSE); VariableDefinePlatformVar(pc, NULL, "_IOLBF", &pc->IntType, (union AnyValue *)&_IOLBFValue, FALSE); VariableDefinePlatformVar(pc, NULL, "_IONBF", &pc->IntType, (union AnyValue *)&_IONBFValue, FALSE); VariableDefinePlatformVar(pc, NULL, "L_tmpnam", &pc->IntType, (union AnyValue *)&L_tmpnamValue, FALSE); VariableDefinePlatformVar(pc, NULL, "GETS_MAX", &pc->IntType, (union AnyValue *)&GETS_MAXValue, FALSE); /* define stdin, stdout and stderr */ VariableDefinePlatformVar(pc, NULL, "stdin", FilePtrType, (union AnyValue *)&stdinValue, FALSE); VariableDefinePlatformVar(pc, NULL, "stdout", FilePtrType, (union AnyValue *)&stdoutValue, FALSE); VariableDefinePlatformVar(pc, NULL, "stderr", FilePtrType, (union AnyValue *)&stderrValue, FALSE); /* define NULL, TRUE and FALSE */ if (!VariableDefined(pc, TableStrRegister(pc, "NULL"))) VariableDefinePlatformVar(pc, NULL, "NULL", &pc->IntType, (union AnyValue *)&Stdio_ZeroValue, FALSE); }
/* parse a statement */ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemicolon) { struct Value *CValue; struct Value *LexerValue; struct Value *VarValue; int Condition; struct ParseState PreState; enum LexToken Token; /* if we're debugging, check for a breakpoint */ if (Parser->DebugMode && Parser->Mode == RunModeRun) DebugCheckStatement(Parser); /* take note of where we are and then grab a token to see what statement we have */ ParserCopy(&PreState, Parser); Token = LexGetToken(Parser, &LexerValue, TRUE); switch (Token) { case TokenEOF: return ParseResultEOF; case TokenIdentifier: /* might be a typedef-typed variable declaration or it might be an expression */ if (VariableDefined(Parser->pc, LexerValue->Val->Identifier)) { VariableGet(Parser->pc, Parser, LexerValue->Val->Identifier, &VarValue); if (VarValue->Typ->Base == Type_Type) { *Parser = PreState; ParseDeclaration(Parser, Token); break; } } else { /* it might be a goto label */ enum LexToken NextToken = LexGetToken(Parser, NULL, FALSE); if (NextToken == TokenColon) { /* declare the identifier as a goto label */ LexGetToken(Parser, NULL, TRUE); if (Parser->Mode == RunModeGoto && LexerValue->Val->Identifier == Parser->SearchGotoLabel) Parser->Mode = RunModeRun; CheckTrailingSemicolon = FALSE; break; } #ifdef FEATURE_AUTO_DECLARE_VARIABLES else /* new_identifier = something */ { /* try to guess type and declare the variable based on assigned value */ if (NextToken == TokenAssign && !VariableDefinedAndOutOfScope(Parser->pc, LexerValue->Val->Identifier)) { if (Parser->Mode == RunModeRun) { struct Value *CValue; char* Identifier = LexerValue->Val->Identifier; LexGetToken(Parser, NULL, TRUE); if (!ExpressionParse(Parser, &CValue)) { ProgramFail(Parser, "expected: expression"); } #if 0 PRINT_SOURCE_POS; PlatformPrintf(Parser->pc->CStdOut, "%t %s = %d;\n", CValue->Typ, Identifier, CValue->Val->Integer); printf("%d\n", VariableDefined(Parser->pc, Identifier)); #endif VariableDefine(Parser->pc, Parser, Identifier, CValue, CValue->Typ, TRUE); break; } } } #endif } /* else fallthrough to expression */ /* no break */ case TokenAsterisk: case TokenAmpersand: case TokenIncrement: case TokenDecrement: case TokenOpenBracket: *Parser = PreState; ExpressionParse(Parser, &CValue); if (Parser->Mode == RunModeRun) VariableStackPop(Parser, CValue); break; case TokenLeftBrace: ParseBlock(Parser, FALSE, TRUE); CheckTrailingSemicolon = FALSE; break; case TokenIf: if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) ProgramFail(Parser, "'(' expected"); Condition = ExpressionParseInt(Parser) != 0; if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) ProgramFail(Parser, "')' expected"); if (ParseStatementMaybeRun(Parser, Condition, TRUE) != ParseResultOk) ProgramFail(Parser, "statement expected"); if (LexGetToken(Parser, NULL, FALSE) == TokenElse) { LexGetToken(Parser, NULL, TRUE); if (ParseStatementMaybeRun(Parser, !Condition, TRUE) != ParseResultOk) ProgramFail(Parser, "statement expected"); } CheckTrailingSemicolon = FALSE; break; case TokenWhile: { struct ParseState PreConditional; enum RunMode PreMode = Parser->Mode; if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) ProgramFail(Parser, "'(' expected"); ParserCopyPos(&PreConditional, Parser); do { ParserCopyPos(Parser, &PreConditional); Condition = ExpressionParseInt(Parser) != 0; if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) ProgramFail(Parser, "')' expected"); if (ParseStatementMaybeRun(Parser, Condition, TRUE) != ParseResultOk) ProgramFail(Parser, "statement expected"); if (Parser->Mode == RunModeContinue) Parser->Mode = PreMode; } while (Parser->Mode == RunModeRun && Condition); if (Parser->Mode == RunModeBreak) Parser->Mode = PreMode; CheckTrailingSemicolon = FALSE; } break; case TokenDo: { struct ParseState PreStatement; enum RunMode PreMode = Parser->Mode; ParserCopyPos(&PreStatement, Parser); do { ParserCopyPos(Parser, &PreStatement); if (ParseStatement(Parser, TRUE) != ParseResultOk) ProgramFail(Parser, "statement expected"); if (Parser->Mode == RunModeContinue) Parser->Mode = PreMode; if (LexGetToken(Parser, NULL, TRUE) != TokenWhile) ProgramFail(Parser, "'while' expected"); if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) ProgramFail(Parser, "'(' expected"); Condition = ExpressionParseInt(Parser) != 0; if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) ProgramFail(Parser, "')' expected"); } while (Condition && Parser->Mode == RunModeRun); if (Parser->Mode == RunModeBreak) Parser->Mode = PreMode; } break; case TokenFor: ParseFor(Parser); CheckTrailingSemicolon = FALSE; break; case TokenSemicolon: CheckTrailingSemicolon = FALSE; break; case TokenIntType: case TokenShortType: case TokenCharType: case TokenLongType: case TokenFloatType: case TokenDoubleType: case TokenVoidType: case TokenStructType: case TokenUnionType: case TokenEnumType: case TokenSignedType: case TokenUnsignedType: case TokenStaticType: case TokenAutoType: case TokenRegisterType: case TokenExternType: *Parser = PreState; CheckTrailingSemicolon = ParseDeclaration(Parser, Token); break; case TokenHashDefine: ParseMacroDefinition(Parser); CheckTrailingSemicolon = FALSE; break; #ifndef NO_HASH_INCLUDE case TokenHashInclude: if (LexGetToken(Parser, &LexerValue, TRUE) != TokenStringConstant) ProgramFail(Parser, "\"filename.h\" expected"); IncludeFile(Parser->pc, (char *)LexerValue->Val->Pointer); CheckTrailingSemicolon = FALSE; break; #endif case TokenSwitch: if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) ProgramFail(Parser, "'(' expected"); Condition = (int) ExpressionParseInt(Parser); if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) ProgramFail(Parser, "')' expected"); if (LexGetToken(Parser, NULL, FALSE) != TokenLeftBrace) ProgramFail(Parser, "'{' expected"); { /* new block so we can store parser state */ enum RunMode OldMode = Parser->Mode; int64_t OldSearchLabel = Parser->SearchLabel; Parser->Mode = RunModeCaseSearch; Parser->SearchLabel = Condition; ParseBlock(Parser, TRUE, (OldMode != RunModeSkip) && (OldMode != RunModeReturn)); if (Parser->Mode != RunModeReturn) Parser->Mode = OldMode; Parser->SearchLabel = OldSearchLabel; } CheckTrailingSemicolon = FALSE; break; case TokenCase: if (Parser->Mode == RunModeCaseSearch) { Parser->Mode = RunModeRun; Condition = (int) ExpressionParseInt(Parser); Parser->Mode = RunModeCaseSearch; } else Condition = (int) ExpressionParseInt(Parser); if (LexGetToken(Parser, NULL, TRUE) != TokenColon) ProgramFail(Parser, "':' expected"); if (Parser->Mode == RunModeCaseSearch && Condition == Parser->SearchLabel) Parser->Mode = RunModeRun; CheckTrailingSemicolon = FALSE; break; case TokenDefault: if (LexGetToken(Parser, NULL, TRUE) != TokenColon) ProgramFail(Parser, "':' expected"); if (Parser->Mode == RunModeCaseSearch) Parser->Mode = RunModeRun; CheckTrailingSemicolon = FALSE; break; case TokenBreak: if (Parser->Mode == RunModeRun) Parser->Mode = RunModeBreak; break; case TokenContinue: if (Parser->Mode == RunModeRun) Parser->Mode = RunModeContinue; break; case TokenReturn: if (Parser->Mode == RunModeRun) { if (!Parser->pc->TopStackFrame || Parser->pc->TopStackFrame->ReturnValue->Typ->Base != TypeVoid) { if (!ExpressionParse(Parser, &CValue)) ProgramFail(Parser, "value required in return"); if (!Parser->pc->TopStackFrame) /* return from top-level program? */ PlatformExit(Parser->pc, (int)ExpressionCoerceLong(CValue)); else ExpressionAssign(Parser, Parser->pc->TopStackFrame->ReturnValue, CValue, TRUE, NULL, 0, FALSE); VariableStackPop(Parser, CValue); } else { if (ExpressionParse(Parser, &CValue)) ProgramFail(Parser, "value in return from a void function"); } Parser->Mode = RunModeReturn; } else ExpressionParse(Parser, &CValue); break; case TokenTypedef: ParseTypedef(Parser); break; case TokenGoto: if (LexGetToken(Parser, &LexerValue, TRUE) != TokenIdentifier) ProgramFail(Parser, "identifier expected"); if (Parser->Mode == RunModeRun) { /* start scanning for the goto label */ Parser->SearchGotoLabel = LexerValue->Val->Identifier; Parser->Mode = RunModeGoto; } break; case TokenDelete: { /* try it as a function or variable name to delete */ if (LexGetToken(Parser, &LexerValue, TRUE) != TokenIdentifier) ProgramFail(Parser, "identifier expected"); if (Parser->Mode == RunModeRun) { /* delete this variable or function */ CValue = TableDelete(Parser->pc, &Parser->pc->GlobalTable, LexerValue->Val->Identifier); if (CValue == NULL) ProgramFail(Parser, "'%s' is not defined", LexerValue->Val->Identifier); VariableFree(Parser->pc, CValue); } break; } default: *Parser = PreState; return ParseResultError; } if (CheckTrailingSemicolon) { if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon) ProgramFail(Parser, "';' expected"); } return ParseResultOk; }
/* creates various system-dependent definitions */ void StringSetupFunc(Picoc *pc) { /* define NULL */ if (!VariableDefined(pc, TableStrRegister(pc, "NULL"))) VariableDefinePlatformVar(pc, NULL, "NULL", &pc->IntType, (union AnyValue *)&String_ZeroValue, FALSE); }
/* parse a statement */ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemicolon) { struct Value *CValue; struct Value *LexerValue; struct Value *VarValue; int Condition; struct ParseState PreState; enum LexToken Token; ParserCopy(&PreState, Parser); Token = LexGetToken(Parser, &LexerValue, TRUE); switch (Token) { case TokenEOF: return ParseResultEOF; case TokenIdentifier: /* might be a typedef-typed variable declaration or it might be an expression */ if (VariableDefined(LexerValue->Val->Identifier)) { VariableGet(Parser, LexerValue->Val->Identifier, &VarValue); if (VarValue->Typ->Base == Type_Type) { *Parser = PreState; ParseDeclaration(Parser, Token); break; } } else { /* it might be a goto label */ enum LexToken NextToken = LexGetToken(Parser, NULL, FALSE); if (NextToken == TokenColon) { /* declare the identifier as a goto label */ LexGetToken(Parser, NULL, TRUE); if (Parser->Mode == RunModeGoto && LexerValue->Val->Identifier == Parser->SearchGotoLabel) Parser->Mode = RunModeRun; CheckTrailingSemicolon = FALSE; break; } } /* else fallthrough to expression */ case TokenAsterisk: case TokenAmpersand: case TokenIncrement: case TokenDecrement: case TokenOpenBracket: *Parser = PreState; ExpressionParse(Parser, &CValue); if (Parser->Mode == RunModeRun) VariableStackPop(Parser, CValue); break; case TokenLeftBrace: ParseBlock(Parser, FALSE, TRUE); CheckTrailingSemicolon = FALSE; break; case TokenIf: if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) ProgramFail(Parser, "'(' expected"); Condition = ExpressionParseInt(Parser); trace_state_print(Parser); if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) ProgramFail(Parser, "')' expected"); if (ParseStatementMaybeRun(Parser, Condition, TRUE) != ParseResultOk) ProgramFail(Parser, "statement expected"); if (LexGetToken(Parser, NULL, FALSE) == TokenElse) { LexGetToken(Parser, NULL, TRUE); if (ParseStatementMaybeRun(Parser, !Condition, TRUE) != ParseResultOk) ProgramFail(Parser, "statement expected"); } CheckTrailingSemicolon = FALSE; break; case TokenWhile: { struct ParseState PreConditional; enum RunMode PreMode = Parser->Mode; if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) ProgramFail(Parser, "'(' expected"); ParserCopyPos(&PreConditional, Parser); do { ParserCopyPos(Parser, &PreConditional); Condition = ExpressionParseInt(Parser); if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) ProgramFail(Parser, "')' expected"); if (ParseStatementMaybeRun(Parser, Condition, TRUE) != ParseResultOk) ProgramFail(Parser, "statement expected"); if (Parser->Mode == RunModeContinue) Parser->Mode = PreMode; } while (Parser->Mode == RunModeRun && Condition); if (Parser->Mode == RunModeBreak) Parser->Mode = PreMode; CheckTrailingSemicolon = FALSE; } break; case TokenDo: { struct ParseState PreStatement; enum RunMode PreMode = Parser->Mode; ParserCopyPos(&PreStatement, Parser); do { ParserCopyPos(Parser, &PreStatement); if (ParseStatement(Parser, TRUE) != ParseResultOk) ProgramFail(Parser, "statement expected"); if (Parser->Mode == RunModeContinue) Parser->Mode = PreMode; if (LexGetToken(Parser, NULL, TRUE) != TokenWhile) ProgramFail(Parser, "'while' expected"); if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) ProgramFail(Parser, "'(' expected"); Condition = ExpressionParseInt(Parser); if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) ProgramFail(Parser, "')' expected"); } while (Condition && Parser->Mode == RunModeRun); if (Parser->Mode == RunModeBreak) Parser->Mode = PreMode; } break; case TokenFor: ParseFor(Parser); //trace_state_print(Parser); CheckTrailingSemicolon = FALSE; break; case TokenSemicolon: CheckTrailingSemicolon = FALSE; break; case TokenIntType: case TokenShortType: case TokenCharType: case TokenLongType: case TokenFloatType: case TokenDoubleType: case TokenVoidType: case TokenStructType: case TokenUnionType: case TokenEnumType: case TokenSignedType: case TokenUnsignedType: case TokenStaticType: case TokenAutoType: case TokenRegisterType: case TokenExternType: *Parser = PreState; CheckTrailingSemicolon = ParseDeclaration(Parser, Token); break; case TokenHashDefine: ParseMacroDefinition(Parser); CheckTrailingSemicolon = FALSE; break; #ifndef NO_HASH_INCLUDE case TokenHashInclude: if (LexGetToken(Parser, &LexerValue, TRUE) != TokenStringConstant) ProgramFail(Parser, "\"filename.h\" expected"); IncludeFile((char *)LexerValue->Val->Pointer); CheckTrailingSemicolon = FALSE; break; #endif case TokenSwitch: if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) ProgramFail(Parser, "'(' expected"); Condition = ExpressionParseInt(Parser); if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) ProgramFail(Parser, "')' expected"); if (LexGetToken(Parser, NULL, FALSE) != TokenLeftBrace) ProgramFail(Parser, "'{' expected"); { /* new block so we can store parser state */ enum RunMode OldMode = Parser->Mode; int OldSearchLabel = Parser->SearchLabel; Parser->Mode = RunModeCaseSearch; Parser->SearchLabel = Condition; ParseBlock(Parser, TRUE, OldMode != RunModeSkip); if (Parser->Mode != RunModeReturn) Parser->Mode = OldMode; Parser->SearchLabel = OldSearchLabel; } CheckTrailingSemicolon = FALSE; break; case TokenCase: if (Parser->Mode == RunModeCaseSearch) { Parser->Mode = RunModeRun; Condition = ExpressionParseInt(Parser); Parser->Mode = RunModeCaseSearch; } else Condition = ExpressionParseInt(Parser); if (LexGetToken(Parser, NULL, TRUE) != TokenColon) ProgramFail(Parser, "':' expected"); if (Parser->Mode == RunModeCaseSearch && Condition == Parser->SearchLabel) Parser->Mode = RunModeRun; CheckTrailingSemicolon = FALSE; break; case TokenDefault: if (LexGetToken(Parser, NULL, TRUE) != TokenColon) ProgramFail(Parser, "':' expected"); if (Parser->Mode == RunModeCaseSearch) Parser->Mode = RunModeRun; CheckTrailingSemicolon = FALSE; break; case TokenBreak: if (Parser->Mode == RunModeRun) Parser->Mode = RunModeBreak; break; case TokenContinue: if (Parser->Mode == RunModeRun) Parser->Mode = RunModeContinue; break; case TokenReturn: if (Parser->Mode == RunModeRun) { if (TopStackFrame->ReturnValue->Typ->Base != TypeVoid) { if (!ExpressionParse(Parser, &CValue)) ProgramFail(Parser, "value required in return"); ExpressionAssign(Parser, TopStackFrame->ReturnValue, CValue, TRUE, NULL, 0, FALSE); VariableStackPop(Parser, CValue); } else { if (ExpressionParse(Parser, &CValue)) ProgramFail(Parser, "value in return from a void function"); } Parser->Mode = RunModeReturn; } else ExpressionParse(Parser, &CValue); break; case TokenTypedef: ParseTypedef(Parser); break; case TokenGoto: if (LexGetToken(Parser, &LexerValue, TRUE) != TokenIdentifier) ProgramFail(Parser, "identifier expected"); if (Parser->Mode == RunModeRun) { /* start scanning for the goto label */ Parser->SearchGotoLabel = LexerValue->Val->Identifier; Parser->Mode = RunModeGoto; } break; case TokenDelete: { /* try it as a function or variable name to delete */ if (LexGetToken(Parser, &LexerValue, TRUE) != TokenIdentifier) ProgramFail(Parser, "identifier expected"); if (Parser->Mode == RunModeRun) { /* delete this variable or function */ CValue = TableDelete(&GlobalTable, LexerValue->Val->Identifier); if (CValue == NULL) ProgramFail(Parser, "'%s' is not defined", LexerValue->Val->Identifier); VariableFree(CValue); } break; } default: *Parser = PreState; return ParseResultError; } if (CheckTrailingSemicolon) { if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon) ProgramFail(Parser, "';' expected"); trace_state_print(Parser); } return ParseResultOk; }
/* creates various system-dependent definitions */ void StringSetupFunc(void) { /* define NULL */ if (!VariableDefined(TableStrRegister("NULL"))) VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); }