diff --git a/Makefile b/Makefile index a2ba9e2..0c9949b 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CFLAGS=-Wall -g #-DDEBUG_LEXER #-DDEBUG_HEAP -DDEBUG_LEXER LIBS=-lm TARGET = picoc -SRCS = picoc.c table.c lex.c parse.c intrinsic.c heap.c type.c variable.c str.c +SRCS = picoc.c table.c lex.c parse.c intrinsic.c heap.c type.c variable.c OBJS := $(SRCS:%.c=%.o) all: $(TARGET) diff --git a/TODO b/TODO index 1968ed3..51d4c79 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,18 @@ TODO * operator precedence * enum * interactive mode +* casts +* change heap to use a single consistent freelist node struct +* periodic heap cleanup +* fix type comparison to take into account array size +* expression and auto-cast support for all types +* octal/hex character constants +* fix #include +* eliminate host printf/scanf use +Need test/debug: +* all break/continue variations +* #define Also: * Remove Var parameter from HeapPopStack() once we're certain it all works diff --git a/intrinsic.c b/intrinsic.c index cc34e66..34edbf3 100644 --- a/intrinsic.c +++ b/intrinsic.c @@ -1,42 +1,168 @@ #include +#include #include +#include #include "picoc.h" -void IntrinsicPrintInt(struct Value *ReturnValue, struct Value **Param) +/* print an integer to a stream without using printf/sprintf */ +void IntrinsicPrintInt(int Num, FILE *Stream) +{ + int Div; + int Remainder = 0; + int Printing = FALSE; + + if (Num < 0) + { + fputc('-', Stream); + Num = -Num; + } + + if (Num == 0) + fputc('0', Stream); + else + { + Div = LARGE_INT_POWER_OF_TEN; + while (Div > 0) + { + Remainder = Num / Div; + if (Printing || Remainder > 0) + { + fputc('0' + Remainder, Stream); + Printing = TRUE; + } + Num -= Remainder * Div; + Div /= 10; + } + } +} + +/* print a double to a stream without using printf/sprintf */ +void IntrinsicPrintFP(double Num, FILE *Stream) +{ + int Exponent = 0; + + if (abs(Num) >= 1e7) + Exponent = log(Num) / LOG10E; + else if (abs(Num) <= 1e-7) + Exponent = log(Num) / LOG10E - 0.999999999; + + Num /= pow(10.0, Exponent); + IntrinsicPrintInt((int)Num, Stream); + fputc('.', Stream); + for (Num -= (int)Num; Num != 0.0; Num *= 10.0) + fputc('0' + (int)Num, Stream); + + if (Exponent) + { + fputc('e', Stream); + IntrinsicPrintInt(Exponent, Stream); + } +} + +/* intrinsic functions made available to the language */ +void IntrinsicPrintInteger(struct Value *ReturnValue, struct Value **Param, int NumArgs) { printf("%d\n", Param[0]->Val->Integer); } -void IntrinsicPrintf(struct Value *ReturnValue, struct Value **Param) +void IntrinsicPrintf(struct Value *ReturnValue, struct Value **Param, int NumArgs) { - printf("IntrinsicPrintf\n"); + struct Value *CharArray = Param[0]->Val->Pointer.Segment; + char *Format; + char *FPos; + struct Value *NextArg = Param[0]; + struct ValueType *FormatType; + int ArgCount = 1; + + if (Param[0]->Val->Pointer.Data.Offset < 0 || Param[0]->Val->Pointer.Data.Offset >= CharArray->Val->Array.Size) + Format = StrEmpty; + else + Format = CharArray->Val->Array.Data + Param[0]->Val->Pointer.Data.Offset; + + for (FPos = Format; *FPos != '\0'; FPos++) + { + if (*FPos == '%') + { + FPos++; + switch (*FPos) + { + case 's': FormatType = CharPtrType; break; + case 'd': FormatType = &IntType; break; + case 'c': FormatType = &CharType; break; + case 'f': FormatType = &FPType; break; + case '%': fputc('%', stdout); FormatType = NULL; break; + case '\0': FPos--; FormatType = NULL; break; + default: putchar(*FPos); FormatType = NULL; break; + } + + if (FormatType != NULL) + { /* we have to format something */ + if (ArgCount >= NumArgs) + fputs("XXX", stdout); /* not enough parameters for format */ + else + { + NextArg = (struct Value *)((void *)NextArg + sizeof(struct Value) + TypeSizeValue(NextArg)); + if (NextArg->Typ != FormatType) + fputs("XXX", stdout); /* bad type for format */ + else + { + switch (*FPos) + { + case 's': + { + struct Value *CharArray = NextArg->Val->Pointer.Segment; + char *Str; + + if (NextArg->Val->Pointer.Data.Offset < 0 || NextArg->Val->Pointer.Data.Offset >= CharArray->Val->Array.Size) + Str = StrEmpty; + else + Str = CharArray->Val->Array.Data + NextArg->Val->Pointer.Data.Offset; + + fputs(Str, stdout); + break; + } + case 'd': IntrinsicPrintInt(NextArg->Val->Integer, stdout); break; + case 'c': fputc(NextArg->Val->Integer, stdout); break; + case 'f': IntrinsicPrintFP(NextArg->Val->FP, stdout); break; + } + } + } + + ArgCount++; + } + } + else + putchar(*FPos); + } } -void IntrinsicSayHello(struct Value *ReturnValue, struct Value **Param) + + +void IntrinsicSayHello(struct Value *ReturnValue, struct Value **Param, int NumArgs) { printf("Hello\n"); } struct IntrinsicFunction { - void (*Func)(struct Value *, struct Value **); + void (*Func)(struct Value *, struct Value **, int); const char *Prototype; } Intrinsics[] = { { IntrinsicSayHello, "void sayhello()" }, { IntrinsicPrintf, "void printf(char *, ...)" }, - { IntrinsicPrintInt, "void printint(int)" }, + { IntrinsicPrintInteger,"void printint(int)" }, }; void IntrinsicInit(struct Table *GlobalTable) { struct ParseState Parser; int Count; - const char *Identifier; + char *Identifier; struct ValueType *ReturnType; struct Value *NewValue; void *Tokens; - const char *IntrinsicName = StrRegister("intrinsic"); + const char *IntrinsicName = TableStrRegister("intrinsic"); for (Count = 0; Count < sizeof(Intrinsics) / sizeof(struct IntrinsicFunction); Count++) { @@ -48,3 +174,39 @@ void IntrinsicInit(struct Table *GlobalTable) HeapFree(Tokens); } } + +#if 0 +void IntrinsicHostPrintf(const char *Format, ...) +{ + va_list Args; + + va_start(Args, Format); + vStrPrintf(Format, Args); + va_end(Args); +} +#endif + +/* printf for compiler error reporting */ +void IntrinsicHostVPrintf(const char *Format, va_list Args) +{ + const char *FPos; + + for (FPos = Format; *FPos != '\0'; FPos++) + { + if (*FPos == '%') + { + FPos++; + switch (*FPos) + { + case 's': fputs(va_arg(Args, char *), stdout); break; + case 'd': IntrinsicPrintInt(va_arg(Args, int), stdout); break; + case 'c': fputc(va_arg(Args, int), stdout); break; + case 'f': IntrinsicPrintFP(va_arg(Args, double), stdout); break; + case '%': fputc('%', stdout); break; + case '\0': FPos--; break; + } + } + else + putchar(*FPos); + } +} diff --git a/lex.c b/lex.c index 79b9f23..98f79eb 100644 --- a/lex.c +++ b/lex.c @@ -56,14 +56,6 @@ static struct ReservedWord ReservedWords[] = { "while", TokenWhile, NULL } }; -struct LexState -{ - const char *Pos; - const char *End; - int Line; - const char *FileName; -}; - /* initialise the lexer */ void LexInit() @@ -71,19 +63,7 @@ void LexInit() int Count; for (Count = 0; Count < sizeof(ReservedWords) / sizeof(struct ReservedWord); Count++) - ReservedWords[Count].SharedWord = StrRegister(ReservedWords[Count].Word); -} - -/* exit with a message */ -void LexFail(struct LexState *Lexer, const char *Message, ...) -{ - va_list Args; - - printf("%s:%d: ", Lexer->FileName, Lexer->Line); - va_start(Args, Message); - vprintf(Message, Args); - printf("\n"); - exit(1); + ReservedWords[Count].SharedWord = TableStrRegister(ReservedWords[Count].Word); } /* check if a word is a reserved word - used while scanning */ @@ -141,11 +121,11 @@ enum LexToken LexGetWord(struct LexState *Lexer, struct Value *Value) while (Lexer->Pos != Lexer->End && isCident(*Pos)) Pos++; - Value->Typ = &StringType; - Value->Val->String = (char *)StrRegister2(Lexer->Pos, Pos - Lexer->Pos); + Value->Typ = NULL; + Value->Val->Identifier = TableStrRegister2(Lexer->Pos, Pos - Lexer->Pos); Lexer->Pos = Pos; - Token = LexCheckReservedWord(Value->Val->String); + Token = LexCheckReservedWord(Value->Val->Identifier); if (Token != TokenNone) return Token; @@ -200,8 +180,8 @@ enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value) const char *EndPos; char *EscBuf; char *EscBufPos; + struct Value *ArrayValue; - Value->Typ = &StringType; while (Lexer->Pos != Lexer->End && (*Lexer->Pos != '"' || Escape)) { /* find the end */ if (Escape) @@ -214,11 +194,21 @@ enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value) 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); - Value->Val->String = (char *)StrRegister2(EscBuf, EscBufPos - EscBuf); + ArrayValue = VariableAllocValueAndData(NULL, sizeof(struct ArrayValue), FALSE, TRUE); + ArrayValue->Typ = CharArrayType; + ArrayValue->Val->Array.Size = EscBufPos - EscBuf + 1; + ArrayValue->Val->Array.Data = TableStrRegister2(EscBuf, EscBufPos - EscBuf); HeapPopStack(EscBuf, EndPos - StartPos); + Value->Typ = CharPtrType; + Value->Val->Pointer.Segment = ArrayValue; + Value->Val->Pointer.Data.Offset = 0; + if (*Lexer->Pos == '"') Lexer->Pos++; @@ -441,7 +431,8 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I { switch (Token) { - case TokenStringConstant: case TokenIdentifier: LexValue.Typ = &StringType; break; + case TokenStringConstant: LexValue.Typ = CharPtrType; break; + case TokenIdentifier: LexValue.Typ = NULL; break; case TokenIntegerConstant: LexValue.Typ = &IntType; break; case TokenCharacterConstant: LexValue.Typ = &CharType; break; case TokenFPConstant: LexValue.Typ = &FPType; break; diff --git a/parse.c b/parse.c index 697602d..be62f15 100644 --- a/parse.c +++ b/parse.c @@ -12,8 +12,8 @@ int ParseStatementMaybeRun(struct ParseState *Parser, int Condition); void ParseInit() { VariableInit(); - IntrinsicInit(&GlobalTable); TypeInit(); + IntrinsicInit(&GlobalTable); } /* do a function call */ @@ -34,6 +34,8 @@ void ParseFunctionCall(struct ParseState *Parser, struct Value **Result, const c *Result = VariableAllocValueFromType(Parser, FuncValue->Val->FuncDef.ReturnType, FALSE); HeapPushStackFrame(); ParamArray = HeapAllocStack(sizeof(struct Value *) * FuncValue->Val->FuncDef.NumParams); + if (ParamArray == NULL) + ProgramFail(Parser, "out of memory"); } /* parse arguments */ @@ -162,12 +164,12 @@ int ParseValue(struct ParseState *Parser, struct Value **Result) case TokenIdentifier: if (LexGetToken(Parser, NULL, FALSE) == TokenOpenBracket) - ParseFunctionCall(Parser, Result, LexValue->Val->String); + ParseFunctionCall(Parser, Result, LexValue->Val->Identifier); else { if (Parser->Mode == RunModeRun) { - VariableGet(Parser, LexValue->Val->String, &LocalLValue); + VariableGet(Parser, LexValue->Val->Identifier, &LocalLValue); if (LocalLValue->Typ->Base == TypeMacro) { struct ParseState MacroLexer = LocalLValue->Val->Parser; @@ -211,11 +213,11 @@ int ParseValue(struct ParseState *Parser, struct Value **Result) if ((*Result)->Typ->Base != TypeArray) ProgramFail(Parser, "not an array"); - if (IntValue < 0 || IntValue >= (*Result)->Typ->ArraySize) + if (IntValue < 0 || IntValue >= (*Result)->Val->Array.Size) ProgramFail(Parser, "illegal array index"); VariableStackPop(Parser, *Result); - *Result = VariableAllocValueFromExistingData(Parser, (*Result)->Typ->FromType, (union AnyValue *)((void *)(*Result)->Val + (*Result)->Typ->FromType->Sizeof * IntValue), TRUE); + *Result = VariableAllocValueFromExistingData(Parser, (*Result)->Typ->FromType, (union AnyValue *)((void *)(*Result)->Val + TypeSize((*Result)->Typ->FromType, 0)), TRUE); } } } @@ -281,8 +283,8 @@ int ParseExpression(struct ParseState *Parser, struct Value **Result) if (TotalValue->Typ->Base != TypeStruct && TotalValue->Typ->Base != TypeUnion) ProgramFail(Parser, "can't use '.' on something that's not a struct or union"); - if (!TableGet(TotalValue->Typ->Members, Ident->Val->String, &CurrentValue)) - ProgramFail(Parser, "structure doesn't have a member called '%s'", Ident->Val->String); + if (!TableGet(TotalValue->Typ->Members, Ident->Val->Identifier, &CurrentValue)) + ProgramFail(Parser, "structure doesn't have a member called '%s'", Ident->Val->Identifier); VariableStackPop(Parser, TotalValue); TotalValue = VariableAllocValueFromExistingData(Parser, CurrentValue->Typ, TotalValueData + CurrentValue->Val->Integer, TRUE); @@ -423,10 +425,10 @@ int ParseIntExpression(struct ParseState *Parser) } /* parse a function definition and store it for later */ -struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, const char *Identifier, int IsPrototype) +struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, char *Identifier, int IsPrototype) { struct ValueType *ParamType; - const char *ParamIdentifier; + char *ParamIdentifier; enum LexToken Token; struct Value *FuncValue; struct ParseState ParamParser; @@ -503,8 +505,8 @@ void ParseMacroDefinition(struct ParseState *Parser) MacroValue->Val->Parser = *Parser; MacroValue->Typ = &MacroType; - if (!TableSet(&GlobalTable, MacroName->Val->String, MacroValue)) - ProgramFail(Parser, "'%s' is already defined", &MacroName->Val->String); + if (!TableSet(&GlobalTable, MacroName->Val->Identifier, MacroValue)) + ProgramFail(Parser, "'%s' is already defined", &MacroName->Val->Identifier); } /* copy where we're at in the parsing */ @@ -624,7 +626,7 @@ int ParseStatement(struct ParseState *Parser) struct Value *CValue; int Condition; struct ParseState PreState = *Parser; - const char *Identifier; + char *Identifier; struct ValueType *Typ; enum LexToken Token = LexGetToken(Parser, NULL, TRUE); @@ -747,7 +749,7 @@ int ParseStatement(struct ParseState *Parser) if (LexGetToken(Parser, &LexerValue, TRUE) != TokenStringConstant) ProgramFail(Parser, "\"filename.h\" expected"); - ScanFile(LexerValue->Val->String); + //ScanFile(LexerValue->Val->String); // XXX - need to dereference char * here break; } @@ -821,7 +823,7 @@ int ParseStatement(struct ParseState *Parser) ProgramFail(Parser, "wrong return type"); // XXX - make assignment a separate function - memcpy(TopStackFrame->ReturnValue->Val, CValue->Val, TopStackFrame->ReturnValue->Typ->Sizeof); + memcpy(TopStackFrame->ReturnValue->Val, CValue->Val, TypeSizeValue(CValue)); Parser->Mode = RunModeReturn; } break; diff --git a/picoc.c b/picoc.c index a3056da..5da516f 100644 --- a/picoc.c +++ b/picoc.c @@ -23,6 +23,18 @@ void ProgramFail(struct ParseState *Parser, const char *Message, ...) exit(1); } +/* exit with a message */ +void LexFail(struct LexState *Lexer, const char *Message, ...) +{ + va_list Args; + + printf("%s:%d: ", Lexer->FileName, Lexer->Line); + va_start(Args, Message); + vprintf(Message, Args); + printf("\n"); + exit(1); +} + /* read a file into memory */ char *ReadFile(const char *FileName) { @@ -33,7 +45,7 @@ char *ReadFile(const char *FileName) if (stat(FileName, &FileInfo)) ProgramFail(NULL, "can't read file %s\n", FileName); - ReadText = HeapAlloc(FileInfo.st_size + 1); + ReadText = malloc(FileInfo.st_size + 1); if (ReadText == NULL) ProgramFail(NULL, "out of memory\n"); @@ -55,7 +67,7 @@ void ScanFile(const char *FileName) { char *SourceStr = ReadFile(FileName); Parse(FileName, SourceStr, strlen(SourceStr), TRUE); - HeapFree(SourceStr); + free(SourceStr); } int main(int argc, char **argv) @@ -64,7 +76,7 @@ int main(int argc, char **argv) ProgramFail(NULL, "Format: picoc ...\n"); HeapInit(); - StrInit(); + TableInit(); VariableInit(); LexInit(); ParseInit(); diff --git a/picoc.h b/picoc.h index f6be7b3..1902118 100644 --- a/picoc.h +++ b/picoc.h @@ -4,7 +4,7 @@ #include /* configurable options */ -#define HEAP_SIZE 8192 /* space for the heap and the stack */ +#define HEAP_SIZE 16384 /* space for the heap and the stack */ #define LARGE_INT_POWER_OF_TEN 1000000000 /* the largest power of ten which fits in an int on this architecture */ #define ARCH_ALIGN_WORDSIZE sizeof(int) /* memory alignment boundary on this architecture */ @@ -37,8 +37,6 @@ #define PATH_MAX 1024 #endif -#define ISVALUETYPE(t) (((t)->Base == TypeInt) || ((t)->Base == TypeFP) || ((t)->Base == TypeString)) - struct Table; /* lexical tokens */ @@ -97,7 +95,6 @@ enum BaseType TypeInt, /* integer */ TypeFP, /* floating point */ TypeChar, /* a single character - acts like an integer except in machine memory access */ - TypeString, /* a constant source text string with C string emulation */ TypeFunction, /* a function */ TypeMacro, /* a macro */ TypePointer, /* a pointer */ @@ -154,7 +151,7 @@ union AnyValue short ShortInteger; int Integer; double FP; - char *String; + char *Identifier; struct ArrayValue Array; struct PointerValue Pointer; struct ParseState Parser; @@ -179,11 +176,11 @@ struct TableEntry { struct ValueEntry { - const char *Key; /* points to the shared string table */ + char *Key; /* points to the shared string table */ struct Value *Val; /* the value we're storing */ } v; /* used for tables of values */ - const char Key[1]; /* dummy size - used for the shared string table */ + char Key[1]; /* dummy size - used for the shared string table */ } p; }; @@ -206,27 +203,41 @@ struct StackFrame struct StackFrame *PreviousStackFrame; /* the next lower stack frame */ }; +/* lexer state */ +struct LexState +{ + const char *Pos; + const char *End; + int Line; + const char *FileName; +}; + /* globals */ extern struct Table GlobalTable; extern struct StackFrame *TopStackFrame; extern struct ValueType IntType; extern struct ValueType CharType; -extern struct ValueType StringType; extern struct ValueType FPType; extern struct ValueType VoidType; extern struct ValueType FunctionType; extern struct ValueType MacroType; -extern const char *StrEmpty; +extern struct ValueType *CharPtrType; +extern struct ValueType *CharArrayType; +extern char *StrEmpty; /* picoc.c */ void ProgramFail(struct ParseState *Parser, const char *Message, ...); +void LexFail(struct LexState *Lexer, const char *Message, ...); void ScanFile(const char *FileName); /* table.c */ -void TableInit(struct Table *Tbl, struct TableEntry **HashTable, int Size, int OnHeap); -int TableSet(struct Table *Tbl, const char *Key, struct Value *Val); +void TableInit(); +char *TableStrRegister(const char *Str); +char *TableStrRegister2(const char *Str, int Len); +void TableInitTable(struct Table *Tbl, struct TableEntry **HashTable, int Size, int OnHeap); +int TableSet(struct Table *Tbl, char *Key, struct Value *Val); int TableGet(struct Table *Tbl, const char *Key, struct Value **Val); -const char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen); +char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen); /* lex.c */ void LexInit(void); @@ -239,17 +250,19 @@ void ParseInit(void); int ParseExpression(struct ParseState *Parser, struct Value **Result); int ParseIntExpression(struct ParseState *Parser); int ParseStatement(struct ParseState *Parser); -struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, const char *Identifier, int IsProtoType); +struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, char *Identifier, int IsProtoType); void Parse(const char *FileName, const char *Source, int SourceLen, int RunIt); /* type.c */ void TypeInit(); -int TypeSizeof(struct ValueType *Typ); -void TypeParse(struct ParseState *Parser, struct ValueType **Typ, const char **Identifier); +int TypeSize(struct ValueType *Typ, int ArraySize); +int TypeSizeValue(struct Value *Val); +void TypeParse(struct ParseState *Parser, struct ValueType **Typ, char **Identifier); struct ValueType *TypeGetMatching(struct ParseState *Parser, struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier); /* intrinsic.c */ void IntrinsicInit(struct Table *GlobalTable); +void IntrinsicHostVPrintf(const char *Format, va_list Args); /* heap.c */ void HeapInit(); @@ -269,15 +282,10 @@ struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue); struct Value *VariableAllocValueFromExistingData(struct ParseState *Parser, struct ValueType *Typ, union AnyValue *FromValue, int IsLValue); struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value *FromValue); -void VariableDefine(struct ParseState *Parser, const char *Ident, struct Value *InitValue); +void VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue); int VariableDefined(const char *Ident); void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal); void VariableStackFrameAdd(struct ParseState *Parser, int NumParams); void VariableStackFramePop(struct ParseState *Parser); -/* str.c */ -void StrInit(); -const char *StrRegister(const char *Str); -const char *StrRegister2(const char *Str, int Len); - #endif /* PICOC_H */ diff --git a/str.c b/str.c deleted file mode 100644 index 964bee0..0000000 --- a/str.c +++ /dev/null @@ -1,123 +0,0 @@ -/* maintains a shared string table so we don't have to worry about string allocation */ -#include -#include -#include -#include -#include -#include "picoc.h" - -struct Table StringTable; -struct TableEntry *StringHashTable[STRING_TABLE_SIZE]; -const char *StrEmpty = NULL; - -/* initialise the shared string system */ -void StrInit() -{ - TableInit(&StringTable, &StringHashTable[0], STRING_TABLE_SIZE, TRUE); - StrEmpty = StrRegister(""); -} - -/* register a string in the shared string store */ -const char *StrRegister2(const char *Str, int Len) -{ - return TableSetIdentifier(&StringTable, Str, Len); -} - -const char *StrRegister(const char *Str) -{ - return StrRegister2(Str, strlen(Str)); -} - -/* print an integer to a stream without using printf/sprintf */ -void StrPrintInt(int Num, FILE *Stream) -{ - int Div; - int Remainder = 0; - int Printing = FALSE; - - if (Num < 0) - { - fputc('-', Stream); - Num = -Num; - } - - if (Num == 0) - fputc('0', Stream); - else - { - Div = LARGE_INT_POWER_OF_TEN; - while (Div > 0) - { - Remainder = Num / Div; - if (Printing || Remainder > 0) - { - fputc('0' + Remainder, Stream); - Printing = TRUE; - } - Num -= Remainder * Div; - Div /= 10; - } - } -} - -/* print a double to a stream without using printf/sprintf */ -void StrPrintFP(double Num, FILE *Stream) -{ - int Exponent = 0; - - if (abs(Num) >= 1e7) - Exponent = log(Num) / LOG10E; - else if (abs(Num) <= 1e-7) - Exponent = log(Num) / LOG10E - 0.999999999; - - Num /= pow(10.0, Exponent); - StrPrintInt((int)Num, Stream); - fputc('.', Stream); - for (Num -= (int)Num; Num != 0.0; Num *= 10.0) - fputc('0' + (int)Num, Stream); - - if (Exponent) - { - fputc('e', Stream); - StrPrintInt(Exponent, Stream); - } -} - -#if 0 -/* Str version of printf */ -void StrPrintf(const char *Format, ...) -{ - va_list Args; - - va_start(Args, Format); - vStrPrintf(Format, Args); - va_end(Args); -} - -void vStrPrintf(const char *Format, va_list Args) -{ - Str *str; - const char *FPos; - - for (FPos = Format; *FPos != '\0'; FPos++) - { - if (*FPos == '%') - { - FPos++; - switch (*FPos) - { - case 'S': str = va_arg(Args, Str *); fwrite(str->Str, 1, str->Len, stdout); break; - case 's': fputs(va_arg(Args, char *), stdout); break; - case 'd': StrPrintInt(va_arg(Args, int), stdout); break; - case 'c': fputc(va_arg(Args, int), stdout); break; - case 'f': StrPrintFP(va_arg(Args, double), stdout); break; - case '%': fputc('%', stdout); break; - case '\0': FPos--; break; - } - } - else - putchar(*FPos); - } -} -#endif - diff --git a/table.c b/table.c index 1f8ab32..08f6af0 100644 --- a/table.c +++ b/table.c @@ -1,6 +1,17 @@ #include #include "picoc.h" +struct Table StringTable; +struct TableEntry *StringHashTable[STRING_TABLE_SIZE]; +char *StrEmpty = NULL; + +/* initialise the shared string system */ +void TableInit() +{ + TableInit(&StringTable, &StringHashTable[0], STRING_TABLE_SIZE, TRUE); + StrEmpty = TableStrRegister(""); +} + /* hash function for strings */ static unsigned int TableHash(const char *Key, int Len) { @@ -20,7 +31,7 @@ static unsigned int TableHash(const char *Key, int Len) } /* initialise a table */ -void TableInit(struct Table *Tbl, struct TableEntry **HashTable, int Size, int OnHeap) +void TableInitTable(struct Table *Tbl, struct TableEntry **HashTable, int Size, int OnHeap) { Tbl->Size = Size; Tbl->OnHeap = OnHeap; @@ -45,8 +56,8 @@ static int TableSearch(struct Table *Tbl, const char *Key, int *AddAt) } /* set an identifier to a value. returns FALSE if it already exists. - * Key must be a shared string from StrRegister() */ -int TableSet(struct Table *Tbl, const char *Key, struct Value *Val) + * Key must be a shared string from TableStrRegister() */ +int TableSet(struct Table *Tbl, char *Key, struct Value *Val) { int AddAt; int HashPos = TableSearch(Tbl, Key, &AddAt); @@ -65,7 +76,7 @@ int TableSet(struct Table *Tbl, const char *Key, struct Value *Val) } /* find a value in a table. returns FALSE if not found. - * Key must be a shared string from StrRegister() */ + * Key must be a shared string from TableStrRegister() */ int TableGet(struct Table *Tbl, const char *Key, struct Value **Val) { int AddAt; @@ -94,7 +105,7 @@ static int TableSearchIdentifier(struct Table *Tbl, const char *Key, int Len, in } /* set an identifier and return the identifier. share if possible */ -const char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen) +char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen) { int AddAt; int HashPos = TableSearchIdentifier(Tbl, Ident, IdentLen, &AddAt); @@ -104,9 +115,23 @@ const char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLe else { /* add it to the table - we economise by not allocating the whole structure here */ struct TableEntry *NewEntry = HeapAlloc(sizeof(struct TableEntry *) + IdentLen + 1); + if (NewEntry == NULL) + ProgramFail(NULL, "out of memory"); + strncpy((char *)&NewEntry->p.Key[0], Ident, IdentLen); NewEntry->Next = Tbl->HashTable[AddAt]; Tbl->HashTable[AddAt] = NewEntry; return &NewEntry->p.Key[0]; } } + +/* register a string in the shared string store */ +char *TableStrRegister2(const char *Str, int Len) +{ + return TableSetIdentifier(&StringTable, Str, Len); +} + +char *TableStrRegister(const char *Str) +{ + return TableStrRegister2(Str, strlen(Str)); +} diff --git a/type.c b/type.c index 4a01a1a..01bd59d 100644 --- a/type.c +++ b/type.c @@ -4,13 +4,15 @@ struct ValueType UberType; struct ValueType IntType; struct ValueType CharType; -struct ValueType StringType; +struct ValueType WordType; struct ValueType FPType; struct ValueType VoidType; struct ValueType FunctionType; struct ValueType MacroType; struct ValueType EnumType; struct ValueType Type_Type; +struct ValueType *CharPtrType; +struct ValueType *CharArrayType; /* add a new type to the set of types we know about */ @@ -52,6 +54,24 @@ struct ValueType *TypeGetMatching(struct ParseState *Parser, struct ValueType *P return TypeAdd(Parser, ParentType, Base, ArraySize, Identifier, Sizeof); } +/* memory used by a value */ +int TypeSizeValue(struct Value *Val) +{ + if (Val->Typ->Base != TypeArray) + return Val->Typ->Sizeof; + else + return Val->Typ->FromType->Sizeof * Val->Val->Array.Size; +} + +/* memory used by a variable given its type and array size */ +int TypeSize(struct ValueType *Typ, int ArraySize) +{ + if (Typ->Base != TypeArray) + return Typ->Sizeof; + else + return Typ->FromType->Sizeof * ArraySize; +} + /* add a base type */ void TypeAddBaseType(struct ValueType *TypeNode, enum BaseType Base, int Sizeof) { @@ -71,13 +91,14 @@ void TypeInit() { UberType.DerivedTypeList = NULL; TypeAddBaseType(&IntType, TypeInt, sizeof(int)); - TypeAddBaseType(&CharType, TypeChar, sizeof(char)); - TypeAddBaseType(&StringType, TypeString, sizeof(const char *)); TypeAddBaseType(&FPType, TypeFP, sizeof(double)); TypeAddBaseType(&VoidType, TypeVoid, 0); TypeAddBaseType(&FunctionType, TypeFunction, sizeof(int)); TypeAddBaseType(&MacroType, TypeMacro, sizeof(int)); TypeAddBaseType(&Type_Type, TypeType, sizeof(struct ValueType *)); + TypeAddBaseType(&CharType, TypeChar, sizeof(char)); + CharPtrType = TypeAdd(NULL, &CharType, TypePointer, 0, StrEmpty, sizeof(char)); + CharArrayType = TypeAdd(NULL, &CharType, TypeArray, 0, StrEmpty, sizeof(char)); } /* parse a struct or union declaration */ @@ -85,7 +106,7 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsSt { struct Value *LexValue; struct ValueType *MemberType; - const char *MemberIdentifier; + char *MemberIdentifier; struct Value *MemberValue; enum LexToken Token; @@ -95,13 +116,13 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsSt if (LexGetToken(Parser, &LexValue, TRUE) != TokenIdentifier) ProgramFail(Parser, "struct/union name required"); - *Typ = TypeGetMatching(Parser, &UberType, IsStruct ? TypeStruct : TypeUnion, 0, LexValue->Val->String); + *Typ = TypeGetMatching(Parser, &UberType, IsStruct ? TypeStruct : TypeUnion, 0, LexValue->Val->Identifier); Token = LexGetToken(Parser, NULL, FALSE); if (Token != TokenLeftBrace) { /* use the already defined structure */ if ((*Typ)->Members == NULL) - ProgramFail(Parser, "structure '%s' isn't defined", LexValue->Val->String); + ProgramFail(Parser, "structure '%s' isn't defined", LexValue->Val->Identifier); return; } @@ -109,7 +130,7 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsSt LexGetToken(Parser, NULL, TRUE); (*Typ)->Members = VariableAlloc(Parser, sizeof(struct Table) + STRUCT_TABLE_SIZE * sizeof(struct TableEntry), TRUE); (*Typ)->Members->HashTable = (void *)(*Typ)->Members + sizeof(struct Table); - TableInit((*Typ)->Members, (void *)(*Typ)->Members + sizeof(struct Table), STRUCT_TABLE_SIZE, TRUE); + TableInitTable((*Typ)->Members, (void *)(*Typ)->Members + sizeof(struct Table), STRUCT_TABLE_SIZE, TRUE); do { TypeParse(Parser, &MemberType, &MemberIdentifier); @@ -142,7 +163,7 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsSt } /* parse a type */ -void TypeParse(struct ParseState *Parser, struct ValueType **Typ, const char **Identifier) +void TypeParse(struct ParseState *Parser, struct ValueType **Typ, char **Identifier) { struct ParseState Before; enum LexToken Token; @@ -189,7 +210,7 @@ void TypeParse(struct ParseState *Parser, struct ValueType **Typ, const char **I if (*Typ == NULL || *Identifier != StrEmpty) ProgramFail(Parser, "bad type declaration"); - *Identifier = LexValue->Val->String; + *Identifier = LexValue->Val->Identifier; Done = TRUE; break; diff --git a/variable.c b/variable.c index 7a4418d..9cd9952 100644 --- a/variable.c +++ b/variable.c @@ -2,6 +2,7 @@ #include #endif #include +#include #include "picoc.h" @@ -16,7 +17,7 @@ struct StackFrame *TopStackFrame = NULL; /* initialise the variable system */ void VariableInit() { - TableInit(&GlobalTable, &GlobalHashTable[0], GLOBAL_TABLE_SIZE, TRUE); + TableInitTable(&GlobalTable, &GlobalHashTable[0], GLOBAL_TABLE_SIZE, TRUE); TopStackFrame = NULL; } @@ -56,7 +57,9 @@ struct Value *VariableAllocValueAndData(struct ParseState *Parser, int DataSize, /* allocate a value given its type */ struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue) { - struct Value *NewValue = VariableAllocValueAndData(Parser, Typ->Sizeof, IsLValue, FALSE); + int Size = TypeSize(Typ, Typ->ArraySize); + struct Value *NewValue = VariableAllocValueAndData(Parser, Size, IsLValue, FALSE); + assert(Size > 0 || Typ == &VoidType); NewValue->Typ = Typ; return NewValue; } @@ -64,9 +67,10 @@ struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct Value /* allocate a value either on the heap or the stack and copy its value */ struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value *FromValue, int OnHeap) { - struct Value *NewValue = VariableAllocValueAndData(Parser, FromValue->Typ->Sizeof, FromValue->IsLValue, OnHeap); + int CopySize = TypeSizeValue(FromValue); + struct Value *NewValue = VariableAllocValueAndData(Parser, CopySize, FromValue->IsLValue, OnHeap); NewValue->Typ = FromValue->Typ; - memcpy(NewValue->Val, FromValue->Val, FromValue->Typ->Sizeof); + memcpy(NewValue->Val, FromValue->Val, CopySize); return NewValue; } @@ -90,7 +94,7 @@ struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value * } /* define a variable */ -void VariableDefine(struct ParseState *Parser, const char *Ident, struct Value *InitValue) +void VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue) { if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, VariableAllocValueAndCopy(Parser, InitValue, TopStackFrame == NULL))) ProgramFail(Parser, "'%s' is already defined", Ident); @@ -127,7 +131,7 @@ void VariableStackPop(struct ParseState *Parser, struct Value *Var) #ifdef DEBUG_HEAP if (Var->ValOnStack) - printf("popping %d at 0x%lx\n", sizeof(struct Value) + Var->Typ->Sizeof, (unsigned long)Var); + printf("popping %d at 0x%lx\n", sizeof(struct Value) + VariableSizeValue(Var), (unsigned long)Var); #endif if (Var->ValOnHeap) @@ -136,7 +140,7 @@ void VariableStackPop(struct ParseState *Parser, struct Value *Var) Success = HeapPopStack(Var, sizeof(struct Value)); /* free from heap */ } else if (Var->ValOnStack) - Success = HeapPopStack(Var, sizeof(struct Value) + Var->Typ->Sizeof); /* free from stack */ + Success = HeapPopStack(Var, sizeof(struct Value) + TypeSizeValue(Var)); /* free from stack */ else Success = HeapPopStack(Var, sizeof(struct Value)); /* value isn't our problem */ @@ -151,9 +155,12 @@ void VariableStackFrameAdd(struct ParseState *Parser, int NumParams) HeapPushStackFrame(); NewFrame = HeapAllocStack(sizeof(struct StackFrame) + sizeof(struct Value *) * NumParams); + if (NewFrame == NULL) + ProgramFail(Parser, "out of memory"); + NewFrame->ReturnParser = *Parser; NewFrame->Parameter = (NumParams > 0) ? ((void *)NewFrame + sizeof(struct StackFrame)) : NULL; - TableInit(&NewFrame->LocalTable, &NewFrame->LocalHashTable[0], LOCAL_TABLE_SIZE, FALSE); + TableInitTable(&NewFrame->LocalTable, &NewFrame->LocalHashTable[0], LOCAL_TABLE_SIZE, FALSE); NewFrame->PreviousStackFrame = TopStackFrame; TopStackFrame = NewFrame; }