/* parse a type - the part at the end after the identifier. eg. array specifications etc. */ struct ValueType *TypeParseBack(struct ParseState *Parser, struct ValueType *FromType) { enum LexToken Token; struct ParseState Before; ParserCopy(&Before, Parser); Token = LexGetToken(Parser, NULL, TRUE); if (Token == TokenLeftSquareBracket) { /* add another array bound */ enum RunMode OldMode = Parser->Mode; int ArraySize; Parser->Mode = RunModeRun; ArraySize = ExpressionParseInt(Parser); Parser->Mode = OldMode; if (LexGetToken(Parser, NULL, TRUE) != TokenRightSquareBracket) ProgramFail(Parser, "']' expected"); return TypeGetMatching(Parser, TypeParseBack(Parser, FromType), TypeArray, ArraySize, StrEmpty, TRUE); } else { /* the type specification has finished */ ParserCopy(Parser, &Before); return FromType; } }
/* parse a type - just the basic type */ int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ, int *IsStatic){ struct ParseState Before; struct Value *LexerValue; enum LexToken Token; int Unsigned = FALSE; struct Value *VarValue; int StaticQualifier = FALSE; Picoc *pc = Parser->pc; *Typ = NULL; /* ignore leading type qualifiers */ ParserCopy(&Before, Parser); Token = LexGetToken(Parser, &LexerValue, TRUE); while (Token == TokenStaticType || Token == TokenAutoType || Token == TokenRegisterType || Token == TokenExternType){ if (Token == TokenStaticType) StaticQualifier = TRUE; Token = LexGetToken(Parser, &LexerValue, TRUE); } if (IsStatic != NULL) *IsStatic = StaticQualifier; /* handle signed/unsigned with no trailing type */ if (Token == TokenSignedType || Token == TokenUnsignedType || Token == TokenLongType){ enum LexToken FollowToken = LexGetToken(Parser, &LexerValue, FALSE); Unsigned = (Token == TokenUnsignedType); if (FollowToken != TokenIntType && FollowToken != TokenLongType && FollowToken != TokenShortType && FollowToken != TokenCharType){ if (Token == TokenUnsignedType) *Typ = &pc->UnsignedIntType; else if (Token == TokenLongType){ if ( FollowToken == TokenDoubleType) *Typ = &pc->FP128Type; else *Typ = &pc->LongType; } else *Typ = &pc->IntType; return TRUE; } Token = LexGetToken(Parser, &LexerValue, TRUE); } switch (Token){ case TokenIntType: *Typ = Unsigned ? &pc->UnsignedIntType : &pc->IntType; break; case TokenShortType: *Typ = Unsigned ? &pc->UnsignedShortType : &pc->ShortType; break; case TokenCharType: *Typ = Unsigned ? &pc->UnsignedCharType : &pc->CharType; break; case TokenLongType: *Typ = Unsigned ? &pc->UnsignedLongType : &pc->LongType; break; #ifndef NO_FP case TokenFloatType: *Typ = &pc->FP32Type;break; case TokenDoubleType: *Typ = &pc->FP64Type; break; case TokenLongDoubleType: *Typ = &pc->FP128Type;break; #endif case TokenVoidType: *Typ = &pc->VoidType; break; case TokenStructType: case TokenUnionType: if (*Typ != NULL) ProgramFail(Parser, "bad type declaration"); TypeParseStruct(Parser, Typ, Token == TokenStructType); break; case TokenEnumType: if (*Typ != NULL) ProgramFail(Parser, "bad type declaration"); TypeParseEnum(Parser, Typ); break; case TokenIdentifier: /* we already know it's a typedef-defined type because we got here */ VariableGet(pc, Parser, LexerValue->Val->Identifier, &VarValue); *Typ = VarValue->Val->Typ; break; default: ParserCopy(Parser, &Before); return FALSE; } return TRUE; }
/* parse a type - the part which is repeated with each identifier in a declaration list */ void TypeParseIdentPart(struct ParseState *Parser, struct ValueType *BasicTyp, struct ValueType **Typ, char **Identifier) { struct ParseState Before; enum LexToken Token; struct Value *LexValue; int Done = FALSE; *Typ = BasicTyp; *Identifier = StrEmpty; while (!Done) { ParserCopy(&Before, Parser); Token = LexGetToken(Parser, &LexValue, TRUE); switch (Token) { case TokenOpenBracket: if (*Typ != NULL) ProgramFail(Parser, "bad type declaration"); TypeParse(Parser, Typ, Identifier, NULL); if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) ProgramFail(Parser, "')' expected"); break; case TokenAsterisk: if (*Typ == NULL) ProgramFail(Parser, "bad type declaration"); *Typ = TypeGetMatching(Parser, *Typ, TypePointer, 0, StrEmpty, TRUE); break; case TokenIdentifier: if (*Typ == NULL || *Identifier != StrEmpty) ProgramFail(Parser, "bad type declaration"); *Identifier = LexValue->Val->Identifier; Done = TRUE; break; default: ParserCopy(Parser, &Before); Done = TRUE; break; } } if (*Typ == NULL) ProgramFail(Parser, "bad type declaration"); if (*Identifier != StrEmpty) { /* parse stuff after the identifier */ *Typ = TypeParseBack(Parser, *Typ); } }
/* handle a #if directive */ void LexHashIf(struct ParseState *Parser) { /* get symbol to check */ struct Value *IdentValue; struct Value *SavedValue; struct ParseState MacroParser; enum LexToken Token = LexGetRawToken(Parser, &IdentValue, TRUE); if (Token == TokenIdentifier) { /* look up a value from a macro definition */ if (!TableGet(&GlobalTable, IdentValue->Val->Identifier, &SavedValue, NULL, NULL, NULL)) ProgramFail(Parser, "'%s' is undefined", IdentValue->Val->Identifier); if (SavedValue->Typ->Base != TypeMacro) ProgramFail(Parser, "value expected"); ParserCopy(&MacroParser, &SavedValue->Val->MacroDef.Body); Token = LexGetRawToken(&MacroParser, &IdentValue, TRUE); } if (Token != TokenCharacterConstant) ProgramFail(Parser, "value expected"); /* is the identifier defined? */ if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel && IdentValue->Val->Character) { /* #if is active, evaluate to this new level */ Parser->HashIfEvaluateToLevel++; } Parser->HashIfLevel++; }
/* remove a stack frame */ void VariableStackFramePop(struct ParseState *Parser) { if (TopStackFrame == NULL) ProgramFail(Parser, "stack is empty - can't go back"); ParserCopy(Parser, &TopStackFrame->ReturnParser); TopStackFrame = TopStackFrame->PreviousStackFrame; HeapPopStackFrame(); }
/* add a stack frame when doing a function call */ void VariableStackFrameAdd(struct ParseState *Parser, const char *FuncName, int NumParams) { struct StackFrame *NewFrame; HeapPushStackFrame(); NewFrame = HeapAllocStack(sizeof(struct StackFrame) + sizeof(struct Value *) * NumParams); if (NewFrame == NULL) ProgramFail(Parser, "out of memory"); ParserCopy(&NewFrame->ReturnParser, Parser); NewFrame->FuncName = FuncName; NewFrame->Parameter = (NumParams > 0) ? ((void *)((char *)NewFrame + sizeof(struct StackFrame))) : NULL; TableInitTable(&NewFrame->LocalTable, &NewFrame->LocalHashTable[0], LOCAL_TABLE_SIZE, FALSE); NewFrame->PreviousStackFrame = TopStackFrame; TopStackFrame = NewFrame; }
/* parse a function definition and store it for later */ struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, char *Identifier) { struct ValueType *ParamType; char *ParamIdentifier; enum LexToken Token = TokenNone; struct ParseState ParamParser; struct Value *FuncValue; struct Value *OldFuncValue; struct ParseState FuncBody; int ParamCount = 0; Picoc *pc = Parser->pc; if (pc->TopStackFrame != NULL) ProgramFail(Parser, "nested function definitions are not allowed"); LexGetToken(Parser, NULL, TRUE); /* open bracket */ ParserCopy(&ParamParser, Parser); ParamCount = ParseCountParams(Parser); if (ParamCount > PARAMETER_MAX) ProgramFail(Parser, "too many parameters (%d allowed)", PARAMETER_MAX); FuncValue = VariableAllocValueAndData(pc, Parser, sizeof(struct FuncDef) + sizeof(struct ValueType *) * ParamCount + sizeof(const char *) * ParamCount, FALSE, NULL, TRUE); FuncValue->Typ = &pc->FunctionType; FuncValue->Val->FuncDef.ReturnType = ReturnType; FuncValue->Val->FuncDef.NumParams = ParamCount; FuncValue->Val->FuncDef.VarArgs = FALSE; FuncValue->Val->FuncDef.ParamType = (struct ValueType **)((char *)FuncValue->Val + sizeof(struct FuncDef)); FuncValue->Val->FuncDef.ParamName = (char **)((char *)FuncValue->Val->FuncDef.ParamType + sizeof(struct ValueType *) * ParamCount); for (ParamCount = 0; ParamCount < FuncValue->Val->FuncDef.NumParams; ParamCount++) { /* harvest the parameters into the function definition */ if (ParamCount == FuncValue->Val->FuncDef.NumParams-1 && LexGetToken(&ParamParser, NULL, FALSE) == TokenEllipsis) { /* ellipsis at end */ FuncValue->Val->FuncDef.NumParams--; FuncValue->Val->FuncDef.VarArgs = TRUE; break; } else { /* add a parameter */ TypeParse(&ParamParser, &ParamType, &ParamIdentifier, NULL); if (ParamType->Base == TypeVoid) { /* this isn't a real parameter at all - delete it */ ParamCount--; FuncValue->Val->FuncDef.NumParams--; } else { FuncValue->Val->FuncDef.ParamType[ParamCount] = ParamType; FuncValue->Val->FuncDef.ParamName[ParamCount] = ParamIdentifier; } } Token = LexGetToken(&ParamParser, NULL, TRUE); if (Token != TokenComma && ParamCount < FuncValue->Val->FuncDef.NumParams-1) ProgramFail(&ParamParser, "comma expected"); } if (FuncValue->Val->FuncDef.NumParams != 0 && Token != TokenCloseBracket && Token != TokenComma && Token != TokenEllipsis) ProgramFail(&ParamParser, "bad parameter"); if (strcmp(Identifier, "main") == 0) { /* make sure it's int main() */ if ( FuncValue->Val->FuncDef.ReturnType != &pc->IntType && FuncValue->Val->FuncDef.ReturnType != &pc->VoidType ) ProgramFail(Parser, "main() should return an int or void"); if (FuncValue->Val->FuncDef.NumParams != 0 && (FuncValue->Val->FuncDef.NumParams != 2 || FuncValue->Val->FuncDef.ParamType[0] != &pc->IntType) ) ProgramFail(Parser, "bad parameters to main()"); } /* look for a function body */ Token = LexGetToken(Parser, NULL, FALSE); if (Token == TokenSemicolon) LexGetToken(Parser, NULL, TRUE); /* it's a prototype, absorb the trailing semicolon */ else { /* it's a full function definition with a body */ if (Token != TokenLeftBrace) ProgramFail(Parser, "bad function definition"); ParserCopy(&FuncBody, Parser); if (ParseStatementMaybeRun(Parser, FALSE, TRUE) != ParseResultOk) ProgramFail(Parser, "function definition expected"); FuncValue->Val->FuncDef.Body = FuncBody; FuncValue->Val->FuncDef.Body.Pos = (unsigned char *) LexCopyTokens(&FuncBody, Parser); /* is this function already in the global table? */ if (TableGet(&pc->GlobalTable, Identifier, &OldFuncValue, NULL, NULL, NULL)) { if (OldFuncValue->Val->FuncDef.Body.Pos == NULL) { /* override an old function prototype */ VariableFree(pc, TableDelete(pc, &pc->GlobalTable, Identifier)); } else ProgramFail(Parser, "'%s' is already defined", Identifier); } } if (!TableSet(pc, &pc->GlobalTable, Identifier, FuncValue, (char *)Parser->FileName, Parser->Line, Parser->CharacterPos)) ProgramFail(Parser, "'%s' is already defined", Identifier); return FuncValue; }
/* 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; }
/* parse a #define macro definition and store it for later */ void ParseMacroDefinition(struct ParseState *Parser) { struct Value *MacroName; char *MacroNameStr; struct Value *ParamName; struct Value *MacroValue; if (LexGetToken(Parser, &MacroName, TRUE) != TokenIdentifier) ProgramFail(Parser, "identifier expected"); MacroNameStr = MacroName->Val->Identifier; if (LexRawPeekToken(Parser) == TokenOpenMacroBracket) { /* it's a parameterised macro, read the parameters */ enum LexToken Token = LexGetToken(Parser, NULL, TRUE); struct ParseState ParamParser; int NumParams; int ParamCount = 0; ParserCopy(&ParamParser, Parser); NumParams = ParseCountParams(&ParamParser); MacroValue = VariableAllocValueAndData(Parser->pc, Parser, sizeof(struct MacroDef) + sizeof(const char *) * NumParams, FALSE, NULL, TRUE); MacroValue->Val->MacroDef.NumParams = NumParams; MacroValue->Val->MacroDef.ParamName = (char **)((char *)MacroValue->Val + sizeof(struct MacroDef)); Token = LexGetToken(Parser, &ParamName, TRUE); while (Token == TokenIdentifier) { /* store a parameter name */ MacroValue->Val->MacroDef.ParamName[ParamCount++] = ParamName->Val->Identifier; /* get the trailing comma */ Token = LexGetToken(Parser, NULL, TRUE); if (Token == TokenComma) Token = LexGetToken(Parser, &ParamName, TRUE); else if (Token != TokenCloseBracket) ProgramFail(Parser, "comma expected"); } if (Token != TokenCloseBracket) ProgramFail(Parser, "close bracket expected"); } else { /* allocate a simple unparameterised macro */ MacroValue = VariableAllocValueAndData(Parser->pc, Parser, sizeof(struct MacroDef), FALSE, NULL, TRUE); MacroValue->Val->MacroDef.NumParams = 0; } /* copy the body of the macro to execute later */ ParserCopy(&MacroValue->Val->MacroDef.Body, Parser); MacroValue->Typ = &Parser->pc->MacroType; LexToEndOfLine(Parser); MacroValue->Val->MacroDef.Body.Pos = (unsigned char *) LexCopyTokens(&MacroValue->Val->MacroDef.Body, Parser); if (!TableSet(Parser->pc, &Parser->pc->GlobalTable, MacroNameStr, MacroValue, (char *)Parser->FileName, Parser->Line, Parser->CharacterPos)) ProgramFail(Parser, "'%s' is already defined", MacroNameStr); }
/* parse an array initialiser and assign to a variable */ int ParseArrayInitialiser(struct ParseState *Parser, struct Value *NewVariable, int DoAssignment) { int ArrayIndex = 0; enum LexToken Token; struct Value *CValue; /* count the number of elements in the array */ if (DoAssignment && Parser->Mode == RunModeRun) { struct ParseState CountParser; int NumElements; ParserCopy(&CountParser, Parser); NumElements = ParseArrayInitialiser(&CountParser, NewVariable, FALSE); if (NewVariable->Typ->Base != TypeArray) AssignFail(Parser, "%t from array initializer", NewVariable->Typ, NULL, 0, 0, NULL, 0); if (NewVariable->Typ->ArraySize == 0) { NewVariable->Typ = TypeGetMatching(Parser->pc, Parser, NewVariable->Typ->FromType, NewVariable->Typ->Base, NumElements, NewVariable->Typ->Identifier, TRUE); VariableRealloc(Parser, NewVariable, TypeSizeValue(NewVariable, FALSE)); } #ifdef DEBUG_ARRAY_INITIALIZER PRINT_SOURCE_POS; printf("array size: %d \n", NewVariable->Typ->ArraySize); #endif } /* parse the array initialiser */ Token = LexGetToken(Parser, NULL, FALSE); while (Token != TokenRightBrace) { if (LexGetToken(Parser, NULL, FALSE) == TokenLeftBrace) { /* this is a sub-array initialiser */ int SubArraySize = 0; struct Value *SubArray = NewVariable; if (Parser->Mode == RunModeRun && DoAssignment) { SubArraySize = TypeSize(NewVariable->Typ->FromType, NewVariable->Typ->FromType->ArraySize, TRUE); SubArray = VariableAllocValueFromExistingData(Parser, NewVariable->Typ->FromType, (union AnyValue *)(&NewVariable->Val->ArrayMem[0] + SubArraySize * ArrayIndex), TRUE, NewVariable); #ifdef DEBUG_ARRAY_INITIALIZER int FullArraySize = TypeSize(NewVariable->Typ, NewVariable->Typ->ArraySize, TRUE); PRINT_SOURCE_POS; PRINT_TYPE(NewVariable->Typ) printf("[%d] subarray size: %d (full: %d,%d) \n", ArrayIndex, SubArraySize, FullArraySize, NewVariable->Typ->ArraySize); #endif if (ArrayIndex >= NewVariable->Typ->ArraySize) ProgramFail(Parser, "too many array elements"); } LexGetToken(Parser, NULL, TRUE); ParseArrayInitialiser(Parser, SubArray, DoAssignment); } else { struct Value *ArrayElement = NULL; if (Parser->Mode == RunModeRun && DoAssignment) { struct ValueType * ElementType = NewVariable->Typ; int TotalSize = 1; int ElementSize = 0; /* int x[3][3] = {1,2,3,4} => handle it just like int x[9] = {1,2,3,4} */ while (ElementType->Base == TypeArray) { TotalSize *= ElementType->ArraySize; ElementType = ElementType->FromType; /* char x[10][10] = {"abc", "def"} => assign "abc" to x[0], "def" to x[1] etc */ if (LexGetToken(Parser, NULL, FALSE) == TokenStringConstant && ElementType->FromType->Base == TypeChar) break; } ElementSize = TypeSize(ElementType, ElementType->ArraySize, TRUE); #ifdef DEBUG_ARRAY_INITIALIZER PRINT_SOURCE_POS; printf("[%d/%d] element size: %d (x%d) \n", ArrayIndex, TotalSize, ElementSize, ElementType->ArraySize); #endif if (ArrayIndex >= TotalSize) ProgramFail(Parser, "too many array elements"); ArrayElement = VariableAllocValueFromExistingData(Parser, ElementType, (union AnyValue *)(&NewVariable->Val->ArrayMem[0] + ElementSize * ArrayIndex), TRUE, NewVariable); } /* this is a normal expression initialiser */ if (!ExpressionParse(Parser, &CValue)) ProgramFail(Parser, "expression expected"); if (Parser->Mode == RunModeRun && DoAssignment) { ExpressionAssign(Parser, ArrayElement, CValue, FALSE, NULL, 0, FALSE); VariableStackPop(Parser, CValue); VariableStackPop(Parser, ArrayElement); } } ArrayIndex++; Token = LexGetToken(Parser, NULL, FALSE); if (Token == TokenComma) { LexGetToken(Parser, NULL, TRUE); Token = LexGetToken(Parser, NULL, FALSE); } else if (Token != TokenRightBrace) ProgramFail(Parser, "comma expected"); } if (Token == TokenRightBrace) LexGetToken(Parser, NULL, TRUE); else ProgramFail(Parser, "'}' expected"); return ArrayIndex; }
/* 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; }