/* 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); }
/* allocate a value given its type */ struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue, struct Value *LValueFrom, int OnHeap) { int Size = TypeSize(Typ, Typ->ArraySize, FALSE); struct Value *NewValue = VariableAllocValueAndData(Parser, Size, IsLValue, LValueFrom, OnHeap); assert(Size > 0 || Typ == &VoidType); NewValue->Typ = Typ; return NewValue; }
/* allocate a value either on the heap or the stack and copy its value. handles overlapping data */ struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value *FromValue, int OnHeap) { struct ValueType *DType = FromValue->Typ; struct Value *NewValue; char TmpBuf[MAX_TMP_COPY_BUF]; int CopySize = TypeSizeValue(FromValue, TRUE); assert(CopySize <= MAX_TMP_COPY_BUF); memcpy((void *)&TmpBuf[0], (void *)FromValue->Val, CopySize); NewValue = VariableAllocValueAndData(Parser, CopySize, FromValue->IsLValue, FromValue->LValueFrom, OnHeap); NewValue->Typ = DType; memcpy((void *)NewValue->Val, (void *)&TmpBuf[0], CopySize); return NewValue; }
/* 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 #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 a struct or union declaration */ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsStruct) { struct Value *LexValue; struct ValueType *MemberType; char *MemberIdentifier; char *StructIdentifier; struct Value *MemberValue; enum LexToken Token; int AlignBoundary; Token = LexGetToken(Parser, &LexValue, FALSE); if (Token == TokenIdentifier) { LexGetToken(Parser, &LexValue, TRUE); StructIdentifier = LexValue->Val->Identifier; Token = LexGetToken(Parser, NULL, FALSE); } else { static char TempNameBuf[7] = "^s0000"; StructIdentifier = PlatformMakeTempName(TempNameBuf); } *Typ = TypeGetMatching(Parser, &UberType, IsStruct ? TypeStruct : TypeUnion, 0, StructIdentifier, Token != TokenLeftBrace); Token = LexGetToken(Parser, NULL, FALSE); if (Token != TokenLeftBrace) { /* use the already defined structure */ if ((*Typ)->Members == NULL) ProgramFail(Parser, "la estructura '%s' no esta definida en este ambito", LexValue->Val->Identifier); return; } if (TopStackFrame != NULL) ProgramFail(Parser, "las estructuras/uniones solo pueden definirse en un ambito global"); LexGetToken(Parser, NULL, TRUE); (*Typ)->Members = VariableAlloc(Parser, sizeof(struct Table) + STRUCT_TABLE_SIZE * sizeof(struct TableEntry), TRUE); (*Typ)->Members->HashTable = (struct TableEntry **)((char *)(*Typ)->Members + sizeof(struct Table)); TableInitTable((*Typ)->Members, (struct TableEntry **)((char *)(*Typ)->Members + sizeof(struct Table)), STRUCT_TABLE_SIZE, TRUE); do { TypeParse(Parser, &MemberType, &MemberIdentifier, NULL); if (MemberType == NULL || MemberIdentifier == NULL) ProgramFail(Parser, "tipo invalido en estructura"); MemberValue = VariableAllocValueAndData(Parser, sizeof(int), FALSE, NULL, TRUE); MemberValue->Typ = MemberType; if (IsStruct) { /* allocate this member's location in the struct */ AlignBoundary = MemberValue->Typ->AlignBytes; if (((*Typ)->Sizeof & (AlignBoundary-1)) != 0) (*Typ)->Sizeof += AlignBoundary - ((*Typ)->Sizeof & (AlignBoundary-1)); MemberValue->Val->Integer = (*Typ)->Sizeof; (*Typ)->Sizeof += TypeSizeValue(MemberValue, TRUE); } else { /* union members always start at 0, make sure it's big enough to hold the largest member */ MemberValue->Val->Integer = 0; if (MemberValue->Typ->Sizeof > (*Typ)->Sizeof) (*Typ)->Sizeof = TypeSizeValue(MemberValue, TRUE); } /* make sure to align to the size of the largest member's alignment */ if ((*Typ)->AlignBytes < MemberValue->Typ->AlignBytes) (*Typ)->AlignBytes = MemberValue->Typ->AlignBytes; /* define it */ if (!TableSet((*Typ)->Members, MemberIdentifier, MemberValue, Parser->FileName, Parser->Line, Parser->CharacterPos)) ProgramFail(Parser, "el miembro '%s' ya esta definido", &MemberIdentifier); if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon) ProgramFail(Parser, "se esperaba un punto y coma"); } while (LexGetToken(Parser, NULL, FALSE) != TokenRightBrace); /* now align the structure to the size of its largest member's alignment */ AlignBoundary = (*Typ)->AlignBytes; if (((*Typ)->Sizeof & (AlignBoundary-1)) != 0) (*Typ)->Sizeof += AlignBoundary - ((*Typ)->Sizeof & (AlignBoundary-1)); LexGetToken(Parser, NULL, TRUE); }
/* get a string constant - used while scanning */ enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value, char EndChar) { int Escape = FALSE; const char *StartPos = Lexer->Pos; const char *EndPos; char *EscBuf; char *EscBufPos; char *RegString; struct Value *ArrayValue; while (Lexer->Pos != Lexer->End && (*Lexer->Pos != EndChar || Escape)) { /* find the end */ if (Escape) { if (*Lexer->Pos == '\r' && Lexer->Pos+1 != Lexer->End) Lexer->Pos++; if (*Lexer->Pos == '\n' && Lexer->Pos+1 != Lexer->End) { Lexer->Line++; Lexer->Pos++; Lexer->CharacterPos = 0; Lexer->EmitExtraNewlines++; } Escape = FALSE; } else if (*Lexer->Pos == '\\') Escape = TRUE; LEXER_INC(Lexer); } EndPos = Lexer->Pos; EscBuf = HeapAllocStack(EndPos - StartPos); if (EscBuf == NULL) LexFail(Lexer, "out of memory"); for (EscBufPos = EscBuf, Lexer->Pos = StartPos; Lexer->Pos != EndPos;) *EscBufPos++ = LexUnEscapeCharacter(&Lexer->Pos, EndPos); /* try to find an existing copy of this string literal */ RegString = TableStrRegister2(EscBuf, EscBufPos - EscBuf); HeapPopStack(EscBuf, EndPos - StartPos); ArrayValue = VariableStringLiteralGet(RegString); if (ArrayValue == NULL) { /* create and store this string literal */ ArrayValue = VariableAllocValueAndData(NULL, 0, FALSE, NULL, TRUE); ArrayValue->Typ = CharArrayType; ArrayValue->Val = (union AnyValue *)RegString; VariableStringLiteralDefine(RegString, ArrayValue); } /* create the the pointer for this char* */ Value->Typ = CharPtrType; Value->Val->Pointer = RegString; if (*Lexer->Pos == EndChar) LEXER_INC(Lexer); return TokenStringConstant; }
/* parse a struct or union declaration */ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsStruct){ struct Value *LexValue; struct ValueType *MemberType; char *MemberIdentifier; char *StructIdentifier; struct Value *MemberValue; enum LexToken Token; int AlignBoundary; Picoc *pc = Parser->pc; Token = LexGetToken(Parser, &LexValue, FALSE); if (Token == TokenIdentifier){ LexGetToken(Parser, &LexValue, TRUE); StructIdentifier = LexValue->Val->Identifier; Token = LexGetToken(Parser, NULL, FALSE); }else{ static char TempNameBuf[7] = "^s0000"; StructIdentifier = PlatformMakeTempName(pc, TempNameBuf); } *Typ = TypeGetMatching(pc, Parser, &Parser->pc->UberType, IsStruct ? TypeStruct : TypeUnion, 0, StructIdentifier, TRUE); if (Token == TokenLeftBrace && (*Typ)->Members) ProgramFail(Parser, "data type '%t' is already defined", *Typ); Token = LexGetToken(Parser, NULL, FALSE); if (Token != TokenLeftBrace){ /* use the already defined structure */ #if 0 if ((*Typ)->Members == NULL) ProgramFail(Parser, "structure '%s' isn't defined", LexValue->Val->Identifier); #endif return; } if (pc->TopStackFrame != NULL) ProgramFail(Parser, "struct/union definitions can only be globals"); LexGetToken(Parser, NULL, TRUE); (*Typ)->Members = VariableAlloc(pc, Parser, sizeof(struct Table) + STRUCT_TABLE_SIZE * sizeof(struct TableEntry), TRUE); (*Typ)->Members->HashTable = (struct TableEntry **)((char *)(*Typ)->Members + sizeof(struct Table)); TableInitTable((*Typ)->Members, (struct TableEntry **)((char *)(*Typ)->Members + sizeof(struct Table)), STRUCT_TABLE_SIZE, TRUE); do { TypeParse(Parser, &MemberType, &MemberIdentifier, NULL); if (!MemberType || !MemberIdentifier) ProgramFail(Parser, "invalid type in struct"); MemberValue = VariableAllocValueAndData(pc, Parser, sizeof(int), FALSE, NULL, TRUE); MemberValue->Typ = MemberType; if (IsStruct){ /* allocate this member's location in the struct */ AlignBoundary = MemberValue->Typ->AlignBytes; if (((*Typ)->Sizeof & (AlignBoundary-1)) != 0) (*Typ)->Sizeof += AlignBoundary - ((*Typ)->Sizeof & (AlignBoundary-1)); MemberValue->Val->Integer = (*Typ)->Sizeof; (*Typ)->Sizeof += TypeSizeValue(MemberValue, TRUE); }else{ /* union members always start at 0, make sure it's big enough to hold the largest member */ MemberValue->Val->Integer = 0; if ((*Typ)->Sizeof < MemberValue->Typ->Sizeof ) (*Typ)->Sizeof = TypeSizeValue(MemberValue, TRUE); } /* make sure to align to the size of the largest member's alignment */ if ((*Typ)->AlignBytes < MemberValue->Typ->AlignBytes) (*Typ)->AlignBytes = MemberValue->Typ->AlignBytes; /* define it */ if (!TableSet(pc, (*Typ)->Members, MemberIdentifier, MemberValue, Parser->FileName, Parser->Line, Parser->CharacterPos)) ProgramFail(Parser, "member '%s' already defined", &MemberIdentifier); if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon) ProgramFail(Parser, "semicolon expected"); } while (LexGetToken(Parser, NULL, FALSE) != TokenRightBrace); /* now align the structure to the size of its largest member's alignment */ AlignBoundary = (*Typ)->AlignBytes; if (((*Typ)->Sizeof & (AlignBoundary-1)) != 0) (*Typ)->Sizeof += AlignBoundary-((*Typ)->Sizeof & (AlignBoundary-1)); LexGetToken(Parser, NULL, TRUE); }