diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c358fc2 --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +CC=gcc +CFLAGS=-Wall -g + +TARGET = picoc +SRCS = picoc.c table.c str.c parse.c lex.c +OBJS := $(SRCS:%.c=%.o) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) -o $(TARGET) $(OBJS) + +clean: + rm -f $(TARGET) $(OBJS) *~ + +count: + wc $(SRCS) picoc.h + +depend: + $(CC) -MM $(SRCS) >.depend + +-include .depend diff --git a/hello.c b/hello.c new file mode 100644 index 0000000..0cf55b8 --- /dev/null +++ b/hello.c @@ -0,0 +1,5 @@ +int main() +{ + printf("Hello world\n"); +} + diff --git a/lex.c b/lex.c new file mode 100644 index 0000000..fd724c3 --- /dev/null +++ b/lex.c @@ -0,0 +1,109 @@ +#include "picoc.h" + +#define LEXINC Lexer->Pos++ +#define NEXTIS(c,x,y) { if (NextChar == (c)) { LEXINC; return (x); } else return (y); } +#define NEXTIS3(c,x,d,y,z) { if (NextChar == (c)) { LEXINC; return (x); } else NEXTIS(d,y,z) } +#define NEXTIS4(c,x,d,y,e,z,a) { if (NextChar == (c)) { LEXINC; return (x); } else NEXTIS3(d,y,e,z,a) } + +struct ReservedWord +{ + const char *Word; + enum LexToken Token; +}; + +static char *ReservedWords[] = +{ + { "char", TokenCharType }, + { "do", TokenDo }, + { "else", TokenElse }, + { "for", TokenFor }, + { "if", TokenIf }, + { "int", TokenIntType }, + { "while", TokenWhile }, + { "void", TokenVoidType } +}; + +void LexInit(struct LexState *Lexer, const Str *Source, int Line) +{ + Lexer->Pos = Source->Str; + Lexer->End = Source->Str + Source->Len; + Lexer->Line = Line; +} + + +enum LexToken LexCheckReservedWord(const Str *Word) +{ + int Count; + + for (Count = 0; Count < sizeof(ReservedWords) / sizeof(struct ReservedWord); Count++) + { + if (StrEqualC(Word, ReservedWord[Count].Word)) + return ReservedWord[Count].Token; + } + + return TokenNone; +} + + +enum LexToken LexGetNumber(struct LexState *Lexer) +{ + XXX +} + + +enum LexToken LexGetWord(struct LexState *Lexer) +{ + XXX +} + + +enum LexToken LexGetToken(struct LexState *Lexer) +{ + char ThisChar; + char NextChar; + + while (Lexer->Pos != Lexer->End && isspace(*Lexer->Pos)) + Lexer->Pos++; + + if (Lexer->Pos == Lexer->End) + return TokenEOF; + + ThisChar = *Lexer->Pos; + if (isCidstart(ThisChar)) + return LexGetWord(Lexer); + + if (isdigit(ThisChar)) + return LexGetNumber(Lexer); + + NextChar = (Lexer->Pos+1 != Lexer->End) ? *(Lexer->Pos+1) : 0; + LEXINC; + switch (ThisChar) + { + case '"': return LexGetStringConstant(Lexer); + case '\'': return LexGetCharacterConstant(Lexer); + case '(': return TokenOpenBracket; + case ')': return TokenCloseBracket; + case '=': NEXTIS('=', TokenEquality, TokenAssignment); + case '+': NEXTIS3('=', TokenAddAssign, '+', TokenIncrement, TokenPlus); + case '-': NEXTIS4('=', TokenSubtractAssign, '>', TokenArrow, '-', TokenDecrement, TokenMinus); + case '*': return TokenAsterisk; + case '/': return TokenSlash; + case '<': NEXTIS('=', TokenLessEqual, TokenLess); + case '>': NEXTIS('=', TokenGreaterEqual, TokenGreater); + case ';': return TokenSemiColon; + case '&': NEXTIS('&', TokenLogicalAnd, TokenAmpersand); + case '|': NEXTIS('|', TokenLogicalOr, TokenArithmeticOr); + case '{': return TokenLeftBrace; + case '}': return TokenRightBrace; + case '[': return TokenLeftAngleBracket; + case ']': return TokenRightAngleBracket; + case '^': return TokenArithmeticExor; + case '~': return TokenUnaryExor; + case ',': return TokenComma; + case '.': return TokenDot; + } + + ProgramError(Lexer->FileName, Lexer->Line, "illegal character '%c'", ThisChar); + return TokenEOF; +} + diff --git a/parse.c b/parse.c new file mode 100644 index 0000000..ef40497 --- /dev/null +++ b/parse.c @@ -0,0 +1,36 @@ +#include + +#include "picoc.h" + +/* the table of global definitions */ +struct Table GlobalTable; +struct TableEntry GlobalHashTable[GLOBAL_TABLE_SIZE]; + + +void ParseInit() +{ + TableInit(&GlobalTable, &GlobalHashTable[0], "global", GLOBAL_TABLE_SIZE); +} + + +/* quick scan a source file for definitions */ +void ParseScan(const Str *FileName, const Str *Source) +{ + enum LexToken Token; + + LexInit(Source); + + while ( (Token = LexGetToken()) != TokenEOF) + { + /* do parsey things here */ + printf("token %d\n", (int)Token); + } +} + + +void ParseCallFunction(const Str *FuncIdent, int argc, char **argv) +{ +} + + + diff --git a/picoc.c b/picoc.c new file mode 100644 index 0000000..61eedde --- /dev/null +++ b/picoc.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include + +#include "picoc.h" + +/* all platform-dependent code is in this file */ + +void Fail(const char *Message, ...) +{ + va_list Args; + + va_start(Args, Message); + vprintf(Message, Args); + exit(1); +} + +void ProgramError(const Str *FileName, int Line, const char *Message, ...) +{ + va_list Args; + + StrPrintf("%S:%d: ", FileName, Line) + va_start(Args, Message); + vprintf(Message, Args); + printf("\n"); + exit(1); +} + +/* read a file into memory. this is the only function using malloc(). + * do it differently for embedded devices without malloc */ +char *ReadFile(const Str *FileName) +{ + struct stat FileInfo; + char *Text; + FILE *InFile; + char CFileName[PATH_MAX]; + + StrToC(CFileName, PATH_MAX, FileName); + + if (stat(CFileName, &FileInfo)) + Fail("can't read file %s\n", CFileName); + + Text = malloc(FileInfo.st_size); + + InFile = fopen(CFileName, "r"); + if (InFile == NULL) + Fail("can't read file %s\n", CFileName); + + if (fread(Text, 1, FileInfo.st_size, InFile) != FileInfo.st_size) + Fail("can't read file %s\n", CFileName); + + fclose(InFile); + + return Text; +} + +/* read and scan a file for definitions */ +void ScanFile(const Str *FileName) +{ + char *Source; + Str SourceStr; + + Source = ReadFile(FileName); + StrFromC(&SourceStr, Source); + ParseScan(FileName, &SourceStr); +} + +int main(int argc, char **argv) +{ + Str FileName; + Str StartFunc; + + printf("picoc\n"); + + if (argc < 2) + Fail("Format: picoc ...\n"); + + ParseInit(); + + StrFromC(&FileName, argv[1]); + ScanFile(&FileName); + + StrFromC(&StartFunc, "main"); + ParseCallFunction(&StartFunc, argc-1, &argv[1]); + + return 0; +} diff --git a/picoc.h b/picoc.h new file mode 100644 index 0000000..a2c6011 --- /dev/null +++ b/picoc.h @@ -0,0 +1,144 @@ +#ifndef PICOC_H +#define PICOC_H + +/* configurable options */ +#define USE_MALLOC +#define GLOBAL_TABLE_SIZE 199 + +/* handy definitions */ +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef min +#define min(x,y) (((x)<(y))?(x):(y)) +#endif + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +/* lexical tokens */ +enum LexToken +{ + TokenNone, + TokenEOF, + TokenIdentifier, + TokenIntegerConstant, + TokenStringConstant, + TokenCharacterConstant, + TokenType, + TokenOpenBracket, + TokenCloseBracket, + TokenAssign, + TokenPlus, + TokenMinus, + TokenAsterisk, + TokenSlash, + TokenEquality, + TokenLessThan, + TokenGreaterThan, + TokenLessEqual, + TokenGreaterEqual, + TokenSemicolon, + TokenArrow, + TokenAmpersand, + TokenLeftBrace, + TokenRightBrace, + TokenLeftAngleBracket, + TokenRightAngleBracket, + TokenLogicalAnd, + TokenLogicalOr, + TokenArithmeticOr, + TokenArithmeticExor, + TokenUnaryExor, + TokenComma, + TokenDot, + TokenAddAssign, + TokenSubtractAssign, + TokenIncrement, + TokenDecrement, + TokenIntType, + TokenCharType, + TokenVoidType, + TokenDo, + TokenElse, + TokenFor, + TokenIf, + TokenWhile +}; + +/* string type so we can use source file strings */ +typedef struct _Str +{ + int Len; + const char *Str; +} Str; + + +/* hash table data structure */ +struct TableEntry +{ + Str Key; + void *Value; +}; + +struct Table +{ + const char *Name; + short Size; + struct TableEntry *HashTable; +}; + + +/* function definition - really just where it is in the source file */ +struct FuncDef +{ + Str Source; + Str FileName; + int StartLine; +}; + + +/* lexer state - so we can lex nested files */ +struct LexState +{ + int Line; + const char *Pos; + const char *End; +}; + + +/* str.c */ +void StrToC(char *Dest, int DestSize, const Str *Source); +void StrFromC(Str *Dest, const char *Source); +int StrEqual(const Str *Str1, const Str *Str2); +int StrEqualC(const Str *Str1, const char *Str2); +void StrPrintf(const str *Format, ...); + +/* picoc.c */ +void Fail(const char *Message, ...); +void ProgramError(const Str *FileName, int Line, const char *Message, ...); +void ScanFile(const Str *FileName); + +/* table.c */ +void TableInit(struct Table *Tbl, struct TableEntry *HashTable, const char *Name, int Size); +void TableSet(struct Table *Tbl, const Str *Key, void *Value); +void *TableLookup(struct Table *Tbl, const Str *Key); + +/* lex.c */ +void LexInit(const Str *Source); +enum LexToken LexGetToken(void); + +/* parse.c */ +void ParseInit(void); +void ParseScan(const Str *FileName, const Str *Source); +void ParseCallFunction(const Str *FuncIdent, int argc, char **argv); + +#endif /* PICOC_H */ + diff --git a/str.c b/str.c new file mode 100644 index 0000000..e108fd2 --- /dev/null +++ b/str.c @@ -0,0 +1,55 @@ +#include +#include +#include + +#include "picoc.h" + + +void StrToC(char *Dest, int DestSize, const Str *Source) +{ + int CopyLen = min(DestSize-1, Source->Len); + memcpy(Dest, Source->Str, CopyLen); + Dest[CopyLen] = '\0'; +} + + +void StrFromC(Str *Dest, const char *Source) +{ + Dest->Str = Source; + Dest->Len = strlen(Source); +} + + +int StrEqual(const Str *Str1, const Str *Str2) +{ + if (Str1->Len != Str2->Len) + return FALSE; + + return memcmp(Str1->Str, Str2->Str, Str1->Len) == 0; +} + + +int StrEqualC(const Str *Str1, const char *Str2) +{ + return strncmp(Str1->Str, Str2, Str1->Len) == 0 && Str2[Str1->Len] == '\0'; +} + + +void StrPrintf(const str *Format, ...) +{ + char FormatBuf[MAX_FORMAT]; + const char *FPos; + char *BPos; + va_list Args; + + va_start(Args, Format); + for (FPos = Format, BPos = &FormatBuf[0]; *FPos != '\0'; FPos++, BPos++) + { + if (*FPos == '%') + { + XXX + } + *BPos = *FPos; + } +} + diff --git a/table.c b/table.c new file mode 100644 index 0000000..7879450 --- /dev/null +++ b/table.c @@ -0,0 +1,122 @@ +#include + +#include "picoc.h" + + +#ifdef USE_MALLOC +#include + + +static unsigned int TableHash(const Str *Key) +{ + unsigned int Hash; + int Count; + int Offset; + const char *KeyPos; + + Hash = Key->Len; + KeyPos = Key->Str; + Offset = 8; + for (Count = 0; Count < Key->Len; Count++, Offset+=7) + { + if (Offset > sizeof(unsigned int) * 8 - 7) + Offset -= (sizeof(unsigned int)-1) * 8; + + Hash ^= *KeyPos++ << Offset; + } + + return Hash; +} + + +void TableInit(struct Table *Tbl, struct TableEntry *HashTable, const char *Name, int Size) +{ + Tbl->Name = Name; + Tbl->Size = Size; + Tbl->HashTable = HashTable; + memset(HashTable, '\0', sizeof(struct TableEntry) * Size); +} + + +static int TableCheckEntry(struct Table *Tbl, const Str *Key, int HashPos) +{ + struct TableEntry *Entry = &Tbl->HashTable[HashPos]; + + if (Entry->Key.Len == 0) + return -1; /* empty */ + + else if (StrEqual(&Entry->Key, Key)) + return HashPos; /* found */ + + else + return -2; /* wrong key */ +} + + +static int TableSearch(struct Table *Tbl, const Str *Key, int *AddAt) +{ + int HashValue; + int HashPos; + int Result; + + HashValue = TableHash(Key) % Tbl->Size; + + for (HashPos = HashValue; HashPos < Tbl->Size; HashPos++) + { + *AddAt = HashPos; + if ( (Result = TableCheckEntry(Tbl, Key, HashPos)) != -2) + return Result; + } + + for (HashPos = 0; HashPos < HashValue; HashPos++) + { + *AddAt = HashPos; + if ( (Result = TableCheckEntry(Tbl, Key, HashPos)) != -2) + return Result; + } + + /* not found and table is full */ + *AddAt = -1; + return -1; +} + + +void TableSet(struct Table *Tbl, const Str *Key, void *Value) +{ + int HashPos; + int AddAt; + + HashPos = TableSearch(Tbl, Key, &AddAt); + + if (HashPos != -1) + Tbl->HashTable[HashPos].Value = Value; /* found - update value */ + else + { + if (AddAt == -1) + Fail("table '%s' is full\n", Tbl->Name); + + else + { /* add it to the table */ + struct TableEntry *Entry = &Tbl->HashTable[AddAt]; + Entry->Key = *Key; + Entry->Value = Value; + } + } +} + + +void *TableLookup(struct Table *Tbl, const Str *Key) +{ + int HashPos; + int AddAt; + + HashPos = TableSearch(Tbl, Key, &AddAt); + + if (HashPos == -1) + return NULL; + else + return Tbl->HashTable[HashPos].Value; +} + +#endif +