/* stack space used by a value */ int TypeStackSizeValue(struct Value *Val) { if (Val != NULL && Val->ValOnStack) return TypeSizeValue(Val, FALSE); else return 0; }
/* free and/or pop the top value off the stack. Var must be the top value on the stack! */ void VariableStackPop(struct ParseState *Parser, struct Value *Var) { int Success; #ifdef DEBUG_HEAP if (Var->ValOnStack) printf("popping %ld at 0x%lx\n", (unsigned long)(sizeof(struct Value) + TypeSizeValue(Var, FALSE)), (unsigned long)Var); #endif if (Var->ValOnHeap) { if (Var->Val != NULL) HeapFreeMem(Var->Val); Success = HeapPopStack(Var, sizeof(struct Value)); /* free from heap */ } else if (Var->ValOnStack) Success = HeapPopStack(Var, sizeof(struct Value) + TypeSizeValue(Var, FALSE)); /* free from stack */ else Success = HeapPopStack(Var, sizeof(struct Value)); /* value isn't our problem */ if (!Success) ProgramFail(Parser, "stack underrun"); }
/* 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 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 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); }
/* 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); }