/* 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); } }
/* define a variable. Ident must be registered. If it's a redefinition from the same declaration don't throw an error */ struct Value *VariableDefineButIgnoreIdentical(struct ParseState *Parser, char *Ident, struct ValueType *Typ, int IsStatic, int *FirstVisit) { struct Value *ExistingValue; const char *DeclFileName; int DeclLine; int DeclColumn; if (IsStatic) { char MangledName[LINEBUFFER_MAX]; char *MNPos = &MangledName[0]; char *MNEnd = &MangledName[LINEBUFFER_MAX-1]; const char *RegisteredMangledName; /* make the mangled static name (avoiding using sprintf() to minimise library impact) */ memset((void *)&MangledName, '\0', sizeof(MangledName)); *MNPos++ = '/'; strncpy(MNPos, (char *)Parser->FileName, MNEnd - MNPos); MNPos += strlen(MNPos); if (TopStackFrame != NULL) { /* we're inside a function */ if (MNEnd - MNPos > 0) *MNPos++ = '/'; strncpy(MNPos, (char *)TopStackFrame->FuncName, MNEnd - MNPos); MNPos += strlen(MNPos); } if (MNEnd - MNPos > 0) *MNPos++ = '/'; strncpy(MNPos, Ident, MNEnd - MNPos); RegisteredMangledName = TableStrRegister(MangledName); /* is this static already defined? */ if (!TableGet(&GlobalTable, RegisteredMangledName, &ExistingValue, &DeclFileName, &DeclLine, &DeclColumn)) { /* define the mangled-named static variable store in the global scope */ ExistingValue = VariableAllocValueFromType(Parser, Typ, TRUE, NULL, TRUE); TableSet(&GlobalTable, (char *)RegisteredMangledName, ExistingValue, (char *)Parser->FileName, Parser->Line, Parser->CharacterPos); *FirstVisit = TRUE; } /* static variable exists in the global scope - now make a mirroring variable in our own scope with the short name */ VariableDefinePlatformVar(Parser, Ident, ExistingValue->Typ, ExistingValue->Val, TRUE); return ExistingValue; } else { if (Parser->Line != 0 && TableGet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, &ExistingValue, &DeclFileName, &DeclLine, &DeclColumn) && DeclFileName == Parser->FileName && DeclLine == Parser->Line && DeclColumn == Parser->CharacterPos) return ExistingValue; else return VariableDefine(Parser, Ident, NULL, Typ, TRUE); } }
/* check if a variable with a given name is defined. Ident must be registered */ int VariableDefined(const char *Ident) { struct Value *FoundValue; if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, &FoundValue, NULL, NULL, NULL)) { if (!TableGet(&GlobalTable, Ident, &FoundValue, NULL, NULL, NULL)) return FALSE; } return TRUE; }
/* 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++; }
void Compiler::CompileSelf() { auto& table = stack_.GetR(GETARG_B(cs_.instr_)); auto& key = stack_.GetRK(GETARG_C(cs_.instr_)); auto& methodslot = stack_.GetR(GETARG_A(cs_.instr_)); auto& selfslot = stack_.GetR(GETARG_A(cs_.instr_) + 1); selfslot.Assign(table); TableGet(cs_, stack_, table, key, methodslot).Compile(); }
/* check if a word is a reserved word - used while scanning */ enum LexToken LexCheckReservedWord(Picoc *pc, const char *Word) { struct Value *val; if (TableGet(&pc->ReservedWordTable, Word, &val, NULL, NULL, NULL)) return ((struct ReservedWord *)val)->Token; else return TokenNone; }
/* get a string literal. assumes that Ident is already registered. NULL if not found */ struct Value *VariableStringLiteralGet(char *Ident) { struct Value *LVal = NULL; if (TableGet(&StringLiteralTable, Ident, &LVal, NULL, NULL, NULL)) return LVal; else return NULL; }
/* 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++; }
/* 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; }
/* 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; }
void Compiler::CompileGettable() { auto& table = stack_.GetR(GETARG_B(cs_.instr_)); auto& key = stack_.GetRK(GETARG_C(cs_.instr_)); auto& dest = stack_.GetR(GETARG_A(cs_.instr_)); TableGet(cs_, stack_, table, key, dest).Compile(); }