diff --git a/Makefile b/Makefile index 90cbea7..5e47407 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,9 @@ CFLAGS=-Wall -pedantic -g -DUNIX_HOST LIBS=-lm TARGET = picoc -SRCS = picoc.c table.c lex.c parse.c expression.c heap.c type.c variable.c clibrary.c library_unix.c platform.c platform_unix.c math_library.c +SRCS = picoc.c table.c lex.c parse.c expression.c heap.c type.c \ + variable.c clibrary.c library_unix.c platform.c platform_unix.c \ + math_library.c include.c library_stdio.c OBJS := $(SRCS:%.c=%.o) all: depend $(TARGET) diff --git a/include.c b/include.c new file mode 100644 index 0000000..989c7de --- /dev/null +++ b/include.c @@ -0,0 +1,60 @@ +#include "picoc.h" + +#ifndef NO_HASH_INCLUDE + +/* a list of libraries we can include */ +struct IncludeLibrary +{ + const char *IncludeName; + void (*SetupFunction)(void); + struct LibraryFunction (*FuncList)[]; + const char *SetupCSource; +}; + +struct IncludeLibrary IncludeLibInfo[] = +{ + { "stdio.h", + &StdioSetupFunc, + &StdioFunctions, + StdioDefs }, + { NULL, NULL, NULL, NULL } +}; + + +/* include one of a number of predefined libraries, or perhaps an actual file */ +void IncludeFile(char *FileName) +{ + struct IncludeLibrary *LInclude; + + /* scan for the include file name to see if it's in our list of predefined includes */ + for (LInclude = &IncludeLibInfo[0]; LInclude->IncludeName != NULL; LInclude++) + { + if (strcmp(LInclude->IncludeName, FileName) == 0) + { + /* found it - protect against multiple inclusion */ + if (!VariableDefined(FileName)) + { + VariableDefine(NULL, FileName, NULL, &VoidType, FALSE); + + /* parse the setup C source code - may define types etc. */ + if (LInclude->SetupFunction != NULL) + (*LInclude->SetupFunction)(); + + /* parse the setup C source code - may define types etc. */ + if (LInclude->SetupCSource != NULL) + Parse(FileName, LInclude->SetupCSource, strlen(LInclude->SetupCSource), TRUE); + + /* set up the library functions */ + if (LInclude->FuncList != NULL) + LibraryInit(&GlobalTable, FileName, LInclude->FuncList); + } + + return; + } + } + + /* not a predefined file, read a real file */ + PlatformScanFile(FileName); +} + +#endif /* NO_HASH_INCLUDE */ diff --git a/lex.c b/lex.c index 717c4a5..8ee7d51 100644 --- a/lex.c +++ b/lex.c @@ -211,6 +211,9 @@ enum LexToken LexGetWord(struct LexState *Lexer, struct Value *Value) Value->Val->Identifier = TableStrRegister2(StartPos, Lexer->Pos - StartPos); Token = LexCheckReservedWord(Value->Val->Identifier); + if (Token == TokenHashInclude) + Lexer->ScanningHashInclude = TRUE; + if (Token != TokenNone) return Token; @@ -270,7 +273,7 @@ unsigned char LexUnEscapeCharacter(const char **From, const char *End) } /* get a string constant - used while scanning */ -enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value) +enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value, char EndChar) { int Escape = FALSE; const char *StartPos = Lexer->Pos; @@ -280,7 +283,7 @@ enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value) char *RegString; struct Value *ArrayValue; - while (Lexer->Pos != Lexer->End && (*Lexer->Pos != '"' || Escape)) + while (Lexer->Pos != Lexer->End && (*Lexer->Pos != EndChar || Escape)) { /* find the end */ if (Escape) @@ -315,7 +318,7 @@ enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value) /* create the the pointer for this char* */ Value->Typ = CharPtrType; Value->Val->NativePointer = RegString; - if (*Lexer->Pos == '"') + if (*Lexer->Pos == EndChar) LEXER_INC(Lexer); return TokenStringConstant; @@ -370,6 +373,7 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) { Lexer->Line++; Lexer->Pos++; + Lexer->ScanningHashInclude = FALSE; #ifdef FANCY_ERROR_REPORTING Lexer->CharacterPos = 0; #endif @@ -393,7 +397,7 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) LEXER_INC(Lexer); switch (ThisChar) { - case '"': GotToken = LexGetStringConstant(Lexer, *Value); break; + case '"': GotToken = LexGetStringConstant(Lexer, *Value, '"'); break; case '\'': GotToken = LexGetCharacterConstant(Lexer, *Value); break; case '(': GotToken = TokenOpenBracket; break; case ')': GotToken = TokenCloseBracket; break; @@ -403,7 +407,7 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) case '*': NEXTIS('=', TokenMultiplyAssign, TokenAsterisk); break; case '/': if (NextChar == '/' || NextChar == '*') LexSkipComment(Lexer, NextChar); else NEXTIS('=', TokenDivideAssign, TokenSlash); break; case '%': NEXTIS('=', TokenModulusAssign, TokenModulus); break; - case '<': NEXTIS3PLUS('=', TokenLessEqual, '<', TokenShiftLeft, '=', TokenShiftLeftAssign, TokenLessThan); break; + case '<': if (Lexer->ScanningHashInclude) GotToken = LexGetStringConstant(Lexer, *Value, '>'); else { NEXTIS3PLUS('=', TokenLessEqual, '<', TokenShiftLeft, '=', TokenShiftLeftAssign, TokenLessThan); } break; case '>': NEXTIS3PLUS('=', TokenGreaterEqual, '>', TokenShiftRight, '=', TokenShiftRightAssign, TokenGreaterThan); break; case ';': GotToken = TokenSemicolon; break; case '&': NEXTIS3('=', TokenArithmeticAndAssign, '&', TokenLogicalAnd, TokenAmpersand); break; @@ -524,6 +528,7 @@ void *LexAnalyse(const char *FileName, const char *Source, int SourceLen, int *T Lexer.End = Source + SourceLen; Lexer.Line = 1; Lexer.FileName = FileName; + Lexer.ScanningHashInclude = FALSE; #ifdef FANCY_ERROR_REPORTING Lexer.CharacterPos = 1; Lexer.SourceText = Source; diff --git a/library_stdio.c b/library_stdio.c new file mode 100644 index 0000000..bd392c9 --- /dev/null +++ b/library_stdio.c @@ -0,0 +1,58 @@ +/* stdio.h library */ +#include "picoc.h" + +#ifndef NO_HASH_INCLUDE + +void StdioFopen(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->NativePointer = fopen(Param[0]->Val->NativePointer, Param[1]->Val->NativePointer); +} + +void StdioFclose(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fclose(Param[0]->Val->NativePointer); +} + +void StdioFread(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fread(Param[0]->Val->NativePointer, Param[1]->Val->Integer, Param[2]->Val->Integer, Param[3]->Val->NativePointer); +} + +void StdioFwrite(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fwrite(Param[0]->Val->NativePointer, Param[1]->Val->Integer, Param[2]->Val->Integer, Param[3]->Val->NativePointer); +} + +void StdioFgetc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fgetc(Param[0]->Val->NativePointer); +} + +void StdioFgets(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->NativePointer = fgets(Param[0]->Val->NativePointer, Param[1]->Val->Integer, Param[2]->Val->NativePointer); +} + +const char StdioDefs[] = "\ +typedef struct FILEStruct FILE; \ +"; + +struct LibraryFunction StdioFunctions[] = +{ + { StdioFopen, "FILE *fopen(char *, char *);" }, + { StdioFclose, "int fclose(FILE *);" }, + { StdioFread, "int fread(void *, int, int, FILE *);" }, + { StdioFwrite, "int fwrite(void *, int, int, FILE *);" }, + { StdioFgetc, "int fgetc(FILE *);" }, + { StdioFgetc, "int getc(FILE *);" }, + { StdioFgets, "char *fgets(char *, int, FILE *);" }, + { NULL, NULL } +}; + +void StdioSetupFunc(void) +{ + /* make a "struct FILEStruct" which is the same size as a native FILE structure */ + TypeCreateOpaqueStruct(NULL, TableStrRegister("FILEStruct"), sizeof(FILE)); +} + +#endif /* NO_HASH_INCLUDE */ diff --git a/library_unix.c b/library_unix.c index 88a18f3..8902452 100644 --- a/library_unix.c +++ b/library_unix.c @@ -10,11 +10,13 @@ void Ctest (struct ParseState *Parser, struct Value *ReturnValue, struct Value * Param[0]->Val->Integer = 1234; } -void Clineno (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { +void Clineno (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ ReturnValue->Val->Integer = Parser->Line; } -void Cerrormsg (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { +void Cerrormsg (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ PlatformErrorPrefix(Parser); LibPrintf(Parser, ReturnValue, Param, NumArgs); } diff --git a/parse.c b/parse.c index 7f51044..4ca6d44 100644 --- a/parse.c +++ b/parse.c @@ -488,7 +488,7 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi if (LexGetToken(Parser, &LexerValue, TRUE) != TokenStringConstant) ProgramFail(Parser, "\"filename.h\" expected"); - PlatformScanFile((char *)LexerValue->Val->NativePointer); + IncludeFile((char *)LexerValue->Val->NativePointer); CheckTrailingSemicolon = FALSE; break; #endif diff --git a/picoc.h b/picoc.h index 7b2366b..af4c532 100644 --- a/picoc.h +++ b/picoc.h @@ -227,6 +227,7 @@ struct LexState const char *End; const char *FileName; int Line; + int ScanningHashInclude; #ifdef FANCY_ERROR_REPORTING int CharacterPos; const char *SourceText; @@ -338,6 +339,7 @@ int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ); void TypeParseIdentPart(struct ParseState *Parser, struct ValueType *BasicTyp, struct ValueType **Typ, char **Identifier); 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); +struct ValueType *TypeCreateOpaqueStruct(struct ParseState *Parser, const char *StructName, int Size); /* heap.c */ void HeapInit(); @@ -398,4 +400,12 @@ void PlatformLibraryInit(); void Initialise(); void Cleanup(); +/* include.c */ +void IncludeFile(char *Filename); + +/* library_stdio.c */ +extern const char StdioDefs[]; +extern struct LibraryFunction StdioFunctions[]; +void StdioSetupFunc(void); + #endif /* PICOC_H */ diff --git a/type.c b/type.c index cf47b2c..fe79ee9 100644 --- a/type.c +++ b/type.c @@ -242,6 +242,20 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsSt LexGetToken(Parser, NULL, TRUE); } +/* create a system struct which has no user-visible members */ +struct ValueType *TypeCreateOpaqueStruct(struct ParseState *Parser, const char *StructName, int Size) +{ + struct ValueType *Typ = TypeGetMatching(Parser, &UberType, TypeStruct, 0, StructName); + + /* create the (empty) table */ + 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); + Typ->Sizeof = Size; + + return Typ; +} + /* parse an enum declaration */ void TypeParseEnum(struct ParseState *Parser, struct ValueType **Typ) {