Initial checkin of picoc. Not working yet.
git-svn-id: http://picoc.googlecode.com/svn/trunk@2 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
parent
bc1b85ab0b
commit
7bfc2c0be5
22
Makefile
Normal file
22
Makefile
Normal file
|
@ -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
|
109
lex.c
Normal file
109
lex.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
36
parse.c
Normal file
36
parse.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
90
picoc.c
Normal file
90
picoc.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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 <program.c> <args>...\n");
|
||||
|
||||
ParseInit();
|
||||
|
||||
StrFromC(&FileName, argv[1]);
|
||||
ScanFile(&FileName);
|
||||
|
||||
StrFromC(&StartFunc, "main");
|
||||
ParseCallFunction(&StartFunc, argc-1, &argv[1]);
|
||||
|
||||
return 0;
|
||||
}
|
144
picoc.h
Normal file
144
picoc.h
Normal file
|
@ -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 */
|
||||
|
55
str.c
Normal file
55
str.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
122
table.c
Normal file
122
table.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "picoc.h"
|
||||
|
||||
|
||||
#ifdef USE_MALLOC
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
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
|
||||
|
Loading…
Reference in a new issue