/* parse a block of code and return what mode it returned in */ enum RunMode ParseBlock(struct ParseState *Parser, int AbsorbOpenBrace, int Condition) { if (AbsorbOpenBrace && LexGetToken(Parser, NULL, TRUE) != TokenLeftBrace) ProgramFail(Parser, "'{' expected"); if (Parser->Mode == RunModeSkip || !Condition) { /* condition failed - skip this block instead */ enum RunMode OldMode = Parser->Mode; Parser->Mode = RunModeSkip; while (ParseStatement(Parser, TRUE) == ParseResultOk) {} Parser->Mode = OldMode; } else { /* just run it in its current mode */ while (ParseStatement(Parser, TRUE) == ParseResultOk) {} } if (LexGetToken(Parser, NULL, TRUE) != TokenRightBrace) ProgramFail(Parser, "'}' expected"); return Parser->Mode; }
/* internal do-anything v[s][n]scanf() formatting system with input from strings or FILE * */ int StdioBaseScanf(struct ParseState *Parser, FILE *Stream, char *StrIn, char *Format, struct StdVararg *Args) { struct Value *ThisArg = Args->Param[0]; int ArgCount = 0; void *ScanfArg[MAX_SCANF_ARGS]; if (Args->NumArgs > MAX_SCANF_ARGS) ProgramFail(Parser, "too many arguments to scanf() - %d max", MAX_SCANF_ARGS); for (ArgCount = 0; ArgCount < Args->NumArgs; ArgCount++) { ThisArg = (struct Value *)((char *)ThisArg + MEM_ALIGN(sizeof(struct Value) + TypeStackSizeValue(ThisArg))); if (ThisArg->Typ->Base == TypePointer) ScanfArg[ArgCount] = ThisArg->Val->Pointer; else if (ThisArg->Typ->Base == TypeArray) ScanfArg[ArgCount] = &ThisArg->Val->ArrayMem[0]; else ProgramFail(Parser, "non-pointer argument to scanf() - argument %d after format", ArgCount+1); } if (Stream != NULL) return fscanf(Stream, Format, ScanfArg[0], ScanfArg[1], ScanfArg[2], ScanfArg[3], ScanfArg[4], ScanfArg[5], ScanfArg[6], ScanfArg[7], ScanfArg[8], ScanfArg[9]); else return sscanf(StrIn, Format, ScanfArg[0], ScanfArg[1], ScanfArg[2], ScanfArg[3], ScanfArg[4], ScanfArg[5], ScanfArg[6], ScanfArg[7], ScanfArg[8], ScanfArg[9]); }
/* read a file into memory */ char *PlatformReadFile(const char *FileName) { struct stat FileInfo; char *ReadText; FILE *InFile; int BytesRead; if (stat(FileName, &FileInfo)) ProgramFail(NULL, "can't read file %s\n", FileName); ReadText = malloc(FileInfo.st_size + 1); if (ReadText == NULL) ProgramFail(NULL, "out of memory\n"); InFile = fopen(FileName, "r"); if (InFile == NULL) ProgramFail(NULL, "can't read file %s\n", FileName); BytesRead = fread(ReadText, 1, FileInfo.st_size, InFile); if (BytesRead == 0) ProgramFail(NULL, "can't read file %s\n", FileName); ReadText[BytesRead] = '\0'; fclose(InFile); return ReadText; }
/* assign an initial value to a variable */ void ParseDeclarationAssignment(struct ParseState *Parser, struct Value *NewVariable, int DoAssignment) { struct Value *CValue; int ArrayIndex; enum LexToken Token = TokenComma; if (LexGetToken(Parser, NULL, FALSE) == TokenLeftBrace) { /* this is an array initialiser */ LexGetToken(Parser, NULL, TRUE); for (ArrayIndex = 0; (Parser->Mode != RunModeRun && Token == TokenComma) || (Parser->Mode == RunModeRun && ArrayIndex < NewVariable->Typ->ArraySize); ArrayIndex++) { struct Value *ArrayElement = NULL; if (Token != TokenComma) ProgramFail(Parser, "comma expected"); if (Parser->Mode == RunModeRun) ArrayElement = VariableAllocValueFromExistingData(Parser, NewVariable->Typ->FromType, (union AnyValue *)(&NewVariable->Val->ArrayMem[0] + TypeSize(NewVariable->Typ->FromType, 0, TRUE) * ArrayIndex), TRUE, NewVariable); 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); } Token = LexGetToken(Parser, NULL, TRUE); } if (Token == TokenComma) Token = LexGetToken(Parser, NULL, TRUE); if (Token != TokenRightBrace) ProgramFail(Parser, "'}' expected"); } else { /* this is a normal expression initialiser */ if (!ExpressionParse(Parser, &CValue)) ProgramFail(Parser, "expression expected"); if (Parser->Mode == RunModeRun && DoAssignment) { ExpressionAssign(Parser, NewVariable, CValue, FALSE, NULL, 0, FALSE); VariableStackPop(Parser, CValue); } } }
/* 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); } }
/* declare a variable or function */ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token) { char *Identifier; struct ValueType *BasicType; struct ValueType *Typ; struct Value *NewVariable = NULL; int IsStatic = FALSE; int FirstVisit = FALSE; Picoc *pc = Parser->pc; TypeParseFront(Parser, &BasicType, &IsStatic); do { TypeParseIdentPart(Parser, BasicType, &Typ, &Identifier); if ((Token != TokenVoidType && Token != TokenStructType && Token != TokenUnionType && Token != TokenEnumType) && Identifier == pc->StrEmpty) ProgramFail(Parser, "identifier expected"); if (Identifier != pc->StrEmpty) { /* handle function definitions */ if (LexGetToken(Parser, NULL, FALSE) == TokenOpenBracket) { ParseFunctionDefinition(Parser, Typ, Identifier); return FALSE; } else { if (Typ == &pc->VoidType && Identifier != pc->StrEmpty) ProgramFail(Parser, "can't define a void variable"); if (Parser->Mode == RunModeRun || Parser->Mode == RunModeGoto) NewVariable = VariableDefineButIgnoreIdentical(Parser, Identifier, Typ, IsStatic, &FirstVisit); if (LexGetToken(Parser, NULL, FALSE) == TokenAssign) { /* we're assigning an initial value */ LexGetToken(Parser, NULL, TRUE); ParseDeclarationAssignment(Parser, NewVariable, !IsStatic || FirstVisit); } } } Token = LexGetToken(Parser, NULL, FALSE); if (Token == TokenComma) LexGetToken(Parser, NULL, TRUE); } while (Token == TokenComma); return TRUE; }
/* 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; } }
/* given a parent type, get a matching derived type and make one if necessary. * Identifier should be registered with the shared string table. */ struct ValueType *TypeGetMatching(struct ParseState *Parser, struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier, int AllowDuplicates) { int Sizeof; int AlignBytes; struct ValueType *ThisType = ParentType->DerivedTypeList; while (ThisType != NULL && (ThisType->Base != Base || ThisType->ArraySize != ArraySize || ThisType->Identifier != Identifier)) ThisType = ThisType->Next; if (ThisType != NULL) { if (AllowDuplicates) return ThisType; else ProgramFail(Parser, "tipo de dato '%s' ya existe", Identifier); } switch (Base) { case TypePointer: Sizeof = sizeof(void *); AlignBytes = PointerAlignBytes; break; case TypeArray: Sizeof = ArraySize * ParentType->Sizeof; AlignBytes = ParentType->AlignBytes; break; case TypeEnum: Sizeof = sizeof(int); AlignBytes = IntAlignBytes; break; default: Sizeof = 0; AlignBytes = 0; break; /* structs and unions will get bigger when we add members to them */ } return TypeAdd(Parser, ParentType, Base, ArraySize, Identifier, Sizeof, AlignBytes); }
/* parse an enum declaration */ void TypeParseEnum(struct ParseState *Parser, struct ValueType **Typ){ struct Value *LexValue; struct Value InitValue; enum LexToken Token; int EnumValue = 0; char *EnumIdentifier; Picoc *pc = Parser->pc; Token = LexGetToken(Parser, &LexValue, FALSE); if (Token == TokenIdentifier){ LexGetToken(Parser, &LexValue, TRUE); EnumIdentifier = LexValue->Val->Identifier; Token = LexGetToken(Parser, NULL, FALSE); } else{ static char TempNameBuf[7] = "^e0000"; EnumIdentifier = PlatformMakeTempName(pc, TempNameBuf); } TypeGetMatching(pc, Parser, &pc->UberType, TypeEnum, 0, EnumIdentifier, Token != TokenLeftBrace); *Typ = &pc->IntType; if (Token != TokenLeftBrace){ /* use the already defined enum */ if ((*Typ)->Members == NULL) ProgramFail(Parser, "enum '%s' isn't defined", EnumIdentifier); return; } if (pc->TopStackFrame != NULL) ProgramFail(Parser, "enum definitions can only be globals"); LexGetToken(Parser, NULL, TRUE); (*Typ)->Members = &pc->GlobalTable; memset((void *)&InitValue, '\0', sizeof(struct Value)); InitValue.Typ = &pc->IntType; InitValue.Val = (union AnyValue *)&EnumValue; do { if (LexGetToken(Parser, &LexValue, TRUE) != TokenIdentifier) ProgramFail(Parser, "identifier expected"); EnumIdentifier = LexValue->Val->Identifier; if (LexGetToken(Parser, NULL, FALSE) == TokenAssign){ LexGetToken(Parser, NULL, TRUE); EnumValue = ExpressionParseInt(Parser); } VariableDefine(pc, Parser, EnumIdentifier, &InitValue, NULL, FALSE); Token = LexGetToken(Parser, NULL, TRUE); if (Token != TokenComma && Token != TokenRightBrace) ProgramFail(Parser, "comma expected"); EnumValue++; } while (Token == TokenComma); }
/* get the value of a variable. must be defined. Ident must be registered */ void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal) { if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, LVal, NULL, NULL, NULL)) { if (!TableGet(&GlobalTable, Ident, LVal, NULL, NULL, NULL)) ProgramFail(Parser, "'%s' is undefined", Ident); } }
/* handle a #endif directive */ void LexHashEndif(struct ParseState *Parser) { if (Parser->HashIfLevel == 0) ProgramFail(Parser, "#endif without #if"); Parser->HashIfLevel--; if (Parser->HashIfEvaluateToLevel > Parser->HashIfLevel) 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(); }
/* define a global variable shared with a platform global. Ident will be registered */ void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct ValueType *Typ, union AnyValue *FromValue, int IsWritable) { struct Value *SomeValue = VariableAllocValueAndData(NULL, 0, IsWritable, NULL, TRUE); SomeValue->Typ = Typ; SomeValue->Val = FromValue; if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, TableStrRegister(Ident), SomeValue, Parser ? Parser->FileName : NULL, Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0)) ProgramFail(Parser, "'%s' is already defined", Ident); }
/* quick scan a source file for definitions */ void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource, int EnableDebugger) { struct ParseState Parser; enum ParseResult Ok; struct CleanupTokenNode *NewCleanupNode; char *RegFileName = TableStrRegister(FileName); void *Tokens = LexAnalyse(RegFileName, Source, SourceLen, NULL); /* allocate a cleanup node so we can clean up the tokens later */ if (!CleanupNow) { NewCleanupNode = HeapAllocMem(sizeof(struct CleanupTokenNode)); if (NewCleanupNode == NULL) ProgramFail(NULL, "out of memory"); NewCleanupNode->Tokens = Tokens; if (CleanupSource) NewCleanupNode->SourceText = Source; else NewCleanupNode->SourceText = NULL; NewCleanupNode->Next = CleanupTokenList; CleanupTokenList = NewCleanupNode; } /* do the parsing */ LexInitParser(&Parser, Source, Tokens, RegFileName, RunIt, EnableDebugger); do { Ok = ParseStatement(&Parser, TRUE); } while (Ok == ParseResultOk); if (Ok == ParseResultError) ProgramFail(&Parser, "parse error"); /* clean up */ if (CleanupNow) HeapFreeMem(Tokens); }
/* handle a #else directive */ void LexHashElse(struct ParseState *Parser) { if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel - 1) Parser->HashIfEvaluateToLevel++; /* #if was not active, make this next section active */ else if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel) { /* #if was active, now go inactive */ if (Parser->HashIfLevel == 0) ProgramFail(Parser, "#else without #if"); Parser->HashIfEvaluateToLevel--; } }
/* like ProgramFail() but gives descriptive error messages for assignment */ void AssignFail(struct ParseState *Parser, const char *Format, struct ValueType *Type1, struct ValueType *Type2, int Num1, int Num2, const char *FuncName, int ParamNo) { PlatformErrorPrefix(Parser); PlatformPrintf("no puedo %s ", (FuncName == NULL) ? "asignar" : "fijar"); if (Type1 != NULL) PlatformPrintf(Format, Type1, Type2); else PlatformPrintf(Format, Num1, Num2); if (FuncName != NULL) PlatformPrintf(" in argument %d of call to %s()", ParamNo, FuncName); ProgramFail(NULL, ""); }
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); } }
/* define a variable. Ident must be registered */ struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable) { struct Value *AssignValue; if (InitValue != NULL) AssignValue = VariableAllocValueAndCopy(Parser, InitValue, TopStackFrame == NULL); else AssignValue = VariableAllocValueFromType(Parser, Typ, MakeWritable, NULL, TopStackFrame == NULL); AssignValue->IsLValue = MakeWritable; if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, AssignValue, Parser ? ((char *)Parser->FileName) : NULL, Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0)) ProgramFail(Parser, "'%s' is already defined", Ident); return AssignValue; }
/* 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; }
/* like ProgramFail() but gives descriptive error messages for assignment */ void AssignFail(struct ParseState *Parser, const char *Format, struct ValueType *Type1, struct ValueType *Type2, int Num1, int Num2, const char *FuncName, int ParamNo) { IOFILE *Stream = Parser->pc->CStdOut; PrintSourceTextErrorLine(Parser->pc->CStdOut, Parser->FileName, Parser->SourceText, Parser->Line, Parser->CharacterPos); PlatformPrintf(Stream, "can't %s ", (FuncName == NULL) ? "assign" : "set"); if (Type1 != NULL) PlatformPrintf(Stream, Format, Type1, Type2); else PlatformPrintf(Stream, Format, Num1, Num2); if (FuncName != NULL) PlatformPrintf(Stream, " in argument %d of call to %s()", ParamNo, FuncName); ProgramFail(Parser, NULL, ""); }
/* allocate some memory, either on the heap or the stack and check if we've run out */ void *VariableAlloc(struct ParseState *Parser, int Size, int OnHeap) { void *NewValue; if (OnHeap) NewValue = HeapAllocMem(Size); else NewValue = HeapAllocStack(Size); if (NewValue == NULL) ProgramFail(Parser, "out of memory"); #ifdef DEBUG_HEAP if (!OnHeap) printf("pushing %d at 0x%lx\n", Size, (unsigned long)NewValue); #endif return NewValue; }
/* set a breakpoint in the table */ void DebugSetBreakpoint(struct ParseState *Parser) { int AddAt; struct TableEntry *FoundEntry = DebugTableSearchBreakpoint(Parser, &AddAt); if (FoundEntry == NULL) { /* add it to the table */ struct TableEntry *NewEntry = HeapAllocMem(sizeof(struct TableEntry)); if (NewEntry == NULL) ProgramFail(NULL, "out of memory"); NewEntry->p.b.FileName = Parser->FileName; NewEntry->p.b.Line = Parser->Line; NewEntry->p.b.CharacterPos = Parser->CharacterPos; NewEntry->Next = BreakpointHashTable[AddAt]; BreakpointHashTable[AddAt] = NewEntry; BreakpointCount++; } }
/* set an identifier and return the identifier. share if possible */ char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen) { /* printf("In TableSetIdentifier %s\n",Ident);*/ int AddAt; struct TableEntry *FoundEntry = TableSearchIdentifier(Tbl, Ident, IdentLen, &AddAt); if (FoundEntry != NULL) return &FoundEntry->p.Key[0]; else { /* add it to the table - we economise by not allocating the whole structure here */ struct TableEntry *NewEntry = HeapAllocMem(sizeof(struct TableEntry) - sizeof(union TableEntryPayload) + IdentLen + 1); if (NewEntry == NULL) ProgramFail(NULL, "out of memory"); strncpy((char *)&NewEntry->p.Key[0], (char *)Ident, IdentLen); NewEntry->p.Key[IdentLen] = '\0'; NewEntry->Next = Tbl->HashTable[AddAt]; Tbl->HashTable[AddAt] = NewEntry; return &NewEntry->p.Key[0]; } }
/* parse interactively */ void PicocParseInteractiveNoStartPrompt(Picoc *pc, int EnableDebugger) { struct ParseState Parser; enum ParseResult Ok; LexInitParser(&Parser, pc, NULL, NULL, pc->StrEmpty, TRUE, EnableDebugger); LexInteractiveClear(pc, &Parser); do { LexInteractiveStatementPrompt(pc); Ok = ParseStatement(&Parser, TRUE); LexInteractiveCompleted(pc, &Parser); } while (Ok == ParseResultOk); if (Ok == ParseResultError) ProgramFail(&Parser, "parse error"); PlatformPrintf(pc, "\n"); }
/* get the value of a variable. must be defined. Ident must be registered */ void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal) { #if ((PICOC_OPTIMIZE_MEMORY == 2) && !defined (BUILTIN_MINI_STDLIB)) int i; unsigned pos; for (i = 0; picoc_rotable[i].pentries; i++) { *LVal = (struct Value *)picoc_auxfind(picoc_rotable[i].pentries, Ident, 0, &pos); if (*LVal) break; } #endif if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, LVal, NULL, NULL, NULL)) { #if ((PICOC_OPTIMIZE_MEMORY == 2) && !defined (BUILTIN_MINI_STDLIB)) if (!TableGet(&GlobalTable, Ident, LVal, NULL, NULL, NULL) && ! *LVal) #else if (!TableGet(&GlobalTable, Ident, LVal, NULL, NULL, NULL)) #endif ProgramFail(Parser, "'%s' is undefined", Ident); } }
/* handle a #ifdef directive */ void LexHashIfdef(struct ParseState *Parser, int IfNot) { /* get symbol to check */ struct Value *IdentValue; struct Value *SavedValue; int IsDefined; enum LexToken Token = LexGetRawToken(Parser, &IdentValue, TRUE); if (Token != TokenIdentifier) ProgramFail(Parser, "identifier expected"); /* is the identifier defined? */ IsDefined = TableGet(&GlobalTable, IdentValue->Val->Identifier, &SavedValue, NULL, NULL, NULL); if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel && ( (IsDefined && !IfNot) || (!IsDefined && IfNot)) ) { /* #if is active, evaluate to this new level */ Parser->HashIfEvaluateToLevel++; } Parser->HashIfLevel++; }
/* parse interactively */ void PicocParseInteractive() { struct ParseState Parser; enum ParseResult Ok; PlatformPrintf(INTERACTIVE_PROMPT_START); LexInitParser(&Parser, NULL, NULL, StrEmpty, TRUE); // PicocPlatformSetExitPoint(); LexInteractiveClear(&Parser); do { LexInteractiveStatementPrompt(); Ok = ParseStatement(&Parser, TRUE); LexInteractiveCompleted(&Parser); } while (Ok == ParseResultOk); if (Ok == ParseResultError) ProgramFail(&Parser, "parse error"); PlatformPrintf("\n"); }
/* picoc: picoc_save_history(filename). only available if linenoise is enabled */ static void picoc_save_history(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { #ifdef BUILD_LINENOISE const char *fname = Param[0]->Val->Identifier; int res; res = linenoise_savehistory(LINENOISE_ID_PICOC, fname); if (res == 0) printf("History saved to %s.\n", fname); else if (res == LINENOISE_HISTORY_NOT_ENABLED) printf("Linenoise not enabled for picoc.\n"); else if (res == LINENOISE_HISTORY_EMPTY) printf("History empty, nothing to save.\n"); else printf("Unable to save history to %s.\n", fname); ReturnValue->Val->Integer = 0; #else ProgramFail(NULL, "Linenoise support was not enabled."); ReturnValue->Val->Integer = -1; #endif /* #ifdef BUILD_LINENOISE */ }
/* assign an initial value to a variable */ void ParseDeclarationAssignment(struct ParseState *Parser, struct Value *NewVariable, int DoAssignment) { struct Value *CValue; if (LexGetToken(Parser, NULL, FALSE) == TokenLeftBrace) { /* this is an array initialiser */ LexGetToken(Parser, NULL, TRUE); ParseArrayInitialiser(Parser, NewVariable, DoAssignment); } else { /* this is a normal expression initialiser */ if (!ExpressionParse(Parser, &CValue)) ProgramFail(Parser, "expression expected"); if (Parser->Mode == RunModeRun && DoAssignment) { ExpressionAssign(Parser, NewVariable, CValue, FALSE, NULL, 0, FALSE); VariableStackPop(Parser, CValue); } } }
/* define a variable. Ident must be registered */ struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable) { struct Value *AssignValue; short int ScopeLevel = Parser ? Parser->ScopeLevel : -1; //~ fprintf(stderr, "def %s %d\n", Ident, ScopeLevel); if (InitValue != NULL) AssignValue = VariableAllocValueAndCopy(Parser, InitValue, TopStackFrame == NULL); else AssignValue = VariableAllocValueFromType(Parser, Typ, MakeWritable, NULL, TopStackFrame == NULL); AssignValue->IsLValue = MakeWritable; AssignValue->ScopeLevel = ScopeLevel; AssignValue->OutOfScope = 0; struct Table * currentTable = (TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable; struct Value * ExistingValue; if (TableGet(currentTable, Ident, &ExistingValue, NULL, NULL, NULL)) { if (ExistingValue->OutOfScope) { //~ fprintf(stderr, "reusing %s\n", Ident); // not sure how to delete properly, so... // throw the old copy away and hope it's cleaned up at VariableStackFramePop TableDeleteStack(currentTable, Ident); } } if (!TableSet(currentTable, Ident, AssignValue, Parser ? ((char *)Parser->FileName) : NULL, Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0)) ProgramFail(Parser, "'%s' is already defined", Ident); return AssignValue; }