Big changes and progress towards the new type system. Doesn't compile right now. Maybe tomorrow.
git-svn-id: http://picoc.googlecode.com/svn/trunk@35 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
parent
a59be13de3
commit
fad5c6db69
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ CFLAGS=-Wall -g
|
|||
LIBS=-lm
|
||||
|
||||
TARGET = picoc
|
||||
SRCS = picoc.c table.c str.c parse.c lex.c intrinsic.c heap.c
|
||||
SRCS = picoc.c table.c str.c parse.c lex.c intrinsic.c heap.c type.c variable.c
|
||||
OBJS := $(SRCS:%.c=%.o)
|
||||
|
||||
all: $(TARGET)
|
||||
|
|
2
TODO
2
TODO
|
@ -17,3 +17,5 @@ New type system:
|
|||
|
||||
Also:
|
||||
* Change function store system to use dynamic allocation
|
||||
* Check for Alloc returns checking NULL
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ void IntrinsicInit(struct Table *GlobalTable)
|
|||
Source.Str = Intrinsics[Count].Prototype;
|
||||
Source.Len = strlen(Source.Str);
|
||||
LexInit(&Lexer, &Source, &IntrinsicFilename, Count+1);
|
||||
ParseType(&Lexer, &Typ);
|
||||
TypeParse(&Lexer, &Typ);
|
||||
LexGetToken(&Lexer, &Identifier);
|
||||
IntrinsicReferenceNo[Count] = -1 - Count;
|
||||
IntrinsicValue[Count].Typ = &FunctionType;
|
||||
|
@ -70,4 +70,3 @@ void IntrinsicCall(struct LexState *Lexer, struct Value *Result, struct ValueTyp
|
|||
Intrinsics[-1-IntrinsicId].Func();
|
||||
Result->Typ = &VoidType;
|
||||
}
|
||||
|
||||
|
|
10
lex.c
10
lex.c
|
@ -29,12 +29,20 @@ static struct ReservedWord ReservedWords[] =
|
|||
{ "do", TokenDo },
|
||||
{ "double", TokenDoubleType },
|
||||
{ "else", TokenElse },
|
||||
{ "enum", TokenEnumType },
|
||||
{ "float", TokenFloatType },
|
||||
{ "for", TokenFor },
|
||||
{ "if", TokenIf },
|
||||
{ "int", TokenIntType },
|
||||
{ "long", TokenLongType },
|
||||
{ "return", TokenReturn },
|
||||
{ "signed", TokenSignedType },
|
||||
{ "short", TokenShortType },
|
||||
{ "struct", TokenStructType },
|
||||
{ "switch", TokenSwitch },
|
||||
{ "typedef", TokenTypedef },
|
||||
{ "union", TokenUnionType },
|
||||
{ "unsigned", TokenUnsignedType },
|
||||
{ "void", TokenVoidType },
|
||||
{ "while", TokenWhile }
|
||||
};
|
||||
|
@ -229,6 +237,7 @@ enum LexToken LexGetToken(struct LexState *Lexer, union AnyValue *Value)
|
|||
}
|
||||
else
|
||||
{
|
||||
CachedPos = Lexer->Pos;
|
||||
CachedToken = LexGetTokenUncached(Lexer, Value);
|
||||
CachedLexer = *Lexer;
|
||||
CachedValue = *Value;
|
||||
|
@ -263,4 +272,3 @@ void LexToEndOfLine(struct LexState *Lexer)
|
|||
while (Lexer->Pos != Lexer->End && *Lexer->Pos != '\n')
|
||||
Lexer->Pos++;
|
||||
}
|
||||
|
||||
|
|
150
parse.c
150
parse.c
|
@ -1,34 +1,12 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "picoc.h"
|
||||
|
||||
/* the table of global definitions */
|
||||
struct Table GlobalTable;
|
||||
struct TableEntry GlobalHashTable[GLOBAL_TABLE_SIZE];
|
||||
|
||||
/* the table of function definitions */
|
||||
struct LexState FunctionStore[FUNCTION_STORE_MAX];
|
||||
int FunctionStoreUsed = 0;
|
||||
|
||||
/* the stack */
|
||||
struct StackFrame Stack[STACK_MAX];
|
||||
int StackUsed = 0;
|
||||
|
||||
/* parameter passing area */
|
||||
struct Value Parameter[PARAMETER_MAX];
|
||||
int ParameterUsed = 0;
|
||||
struct Value ReturnValue;
|
||||
|
||||
/* some basic types */
|
||||
struct ValueType IntType;
|
||||
struct ValueType CharType;
|
||||
struct ValueType StringType;
|
||||
struct ValueType FPType;
|
||||
struct ValueType VoidType;
|
||||
struct ValueType FunctionType;
|
||||
struct ValueType MacroType;
|
||||
|
||||
/* local prototypes */
|
||||
int ParseExpression(struct LexState *Lexer, struct Value *Result, int RunIt);
|
||||
void ParseIntExpression(struct LexState *Lexer, struct Value *Result, int RunIt);
|
||||
|
@ -39,118 +17,9 @@ int ParseArguments(struct LexState *Lexer, int RunIt);
|
|||
/* initialise the parser */
|
||||
void ParseInit()
|
||||
{
|
||||
TableInit(&GlobalTable, &GlobalHashTable[0], GLOBAL_TABLE_SIZE);
|
||||
VariableInit();
|
||||
IntrinsicInit(&GlobalTable);
|
||||
IntType.Base = TypeInt;
|
||||
IntType.SubType = NULL;
|
||||
CharType.Base = TypeChar;
|
||||
CharType.SubType = NULL;
|
||||
StringType.Base = TypeString;
|
||||
StringType.SubType = NULL;
|
||||
FPType.Base = TypeFP;
|
||||
FPType.SubType = NULL;
|
||||
VoidType.Base = TypeVoid;
|
||||
VoidType.SubType = NULL;
|
||||
FunctionType.Base = TypeFunction;
|
||||
FunctionType.SubType = NULL;
|
||||
MacroType.Base = TypeMacro;
|
||||
MacroType.SubType = NULL;
|
||||
}
|
||||
|
||||
/* find out the size of a type */
|
||||
int ParseSizeofType(struct ValueType *Typ)
|
||||
{
|
||||
switch (Typ->Base)
|
||||
{
|
||||
case TypeVoid: return 0;
|
||||
case TypeInt: return sizeof(int);
|
||||
case TypeFP: return sizeof(double);
|
||||
case TypeChar: return sizeof(char);
|
||||
case TypeString: return sizeof(Str);
|
||||
case TypeFunction: return sizeof(int);
|
||||
case TypeMacro: return sizeof(int);
|
||||
case TypePointer: return sizeof(struct PointerValue);
|
||||
case TypeArray: return 0; // XXX - fixme
|
||||
case TypeType: return sizeof(struct ValueType *);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* allocate a value either on the heap or the stack using space dependent on what type we want */
|
||||
struct Value *ParseAllocValueFromType(struct ValueType *Typ)
|
||||
{
|
||||
struct Value *NewValue;
|
||||
|
||||
if (StackUsed == 0)
|
||||
{ /* it's a global */
|
||||
NewValue = HeapAlloc(sizeof(struct Value) + ParseSizeofType(Typ));
|
||||
NewValue->MustFree = TRUE;
|
||||
}
|
||||
else
|
||||
{ /* allocated on the stack */
|
||||
NewValue = HeapAllocStack(sizeof(struct Value) + ParseSizeofType(Typ));
|
||||
NewValue->MustFree = FALSE;
|
||||
}
|
||||
|
||||
NewValue->Typ = Typ;
|
||||
NewValue->Val = (union AnyValue *)((void *)NewValue + sizeof(struct Value));
|
||||
|
||||
return NewValue;
|
||||
}
|
||||
|
||||
/* allocate a value either on the heap or the stack and copy its value */
|
||||
struct Value *ParseAllocValueAndCopy(struct Value *FromValue)
|
||||
{
|
||||
struct Value *NewValue = ParseAllocValueFromType(FromValue->Typ);
|
||||
memcpy(NewValue->Val, FromValue->Val, ParseSizeofType(FromValue->Typ));
|
||||
return NewValue;
|
||||
}
|
||||
|
||||
/* define a variable */
|
||||
void VariableDefine(struct LexState *Lexer, const Str *Ident, struct Value *InitValue)
|
||||
{
|
||||
if (!TableSet((StackUsed == 0) ? &GlobalTable : &Stack[StackUsed-1].LocalTable, Ident, ParseAllocValueAndCopy(InitValue)))
|
||||
ProgramFail(Lexer, "'%S' is already defined", Ident);
|
||||
}
|
||||
|
||||
/* get the value of a variable. must be defined */
|
||||
void VariableGet(struct LexState *Lexer, Str *Ident, struct Value *Val, struct Value **LVal)
|
||||
{
|
||||
if (StackUsed == 0 || !TableGet(&Stack[StackUsed-1].LocalTable, Ident, LVal))
|
||||
{
|
||||
if (!TableGet(&GlobalTable, Ident, LVal))
|
||||
ProgramFail(Lexer, "'%S' is undefined", Ident);
|
||||
}
|
||||
|
||||
*Val = **LVal;
|
||||
}
|
||||
|
||||
/* add a stack frame when doing a function call */
|
||||
void StackFrameAdd(struct LexState *Lexer)
|
||||
{
|
||||
struct StackFrame *NewFrame = &Stack[StackUsed];
|
||||
|
||||
if (StackUsed >= STACK_MAX)
|
||||
ProgramFail(Lexer, "too many nested function calls");
|
||||
|
||||
NewFrame->ReturnLex = *Lexer;
|
||||
TableInit(&NewFrame->LocalTable, &NewFrame->LocalHashTable[0], LOCAL_TABLE_SIZE);
|
||||
StackUsed++;
|
||||
}
|
||||
|
||||
/* parse a type specification */
|
||||
int ParseType(struct LexState *Lexer, struct ValueType **Typ)
|
||||
{
|
||||
struct LexState Before = *Lexer;
|
||||
enum LexToken Token = LexGetPlainToken(Lexer);
|
||||
switch (Token)
|
||||
{
|
||||
case TokenIntType: case TokenCharType: *Typ = &IntType; return TRUE;
|
||||
case TokenFloatType: case TokenDoubleType: *Typ = &FPType; return TRUE;
|
||||
case TokenVoidType: *Typ = &VoidType; return TRUE;
|
||||
default: *Lexer = Before; return FALSE;
|
||||
}
|
||||
TypeInit();
|
||||
}
|
||||
|
||||
/* parse a parameter list, defining parameters as local variables in the current scope */
|
||||
|
@ -163,7 +32,7 @@ void ParseParameterList(struct LexState *CallLexer, struct LexState *FuncLexer,
|
|||
|
||||
for (ParamCount = 0; ParamCount < ParameterUsed; ParamCount++)
|
||||
{
|
||||
ParseType(FuncLexer, &Typ);
|
||||
TypeParse(FuncLexer, &Typ);
|
||||
Token = LexGetToken(FuncLexer, &Identifier);
|
||||
if (Token != TokenComma && Token != TokenCloseBracket)
|
||||
{ /* there's an identifier */
|
||||
|
@ -226,13 +95,13 @@ void ParseFunctionCall(struct LexState *Lexer, struct Value *Result, Str *FuncNa
|
|||
if (Result->Typ->Base != TypeFunction)
|
||||
ProgramFail(Lexer, "not a function - can't call");
|
||||
|
||||
StackFrameAdd(Lexer);
|
||||
VariableStackFrameAdd(Lexer);
|
||||
if (Result->Val->Integer >= 0)
|
||||
FuncLexer = FunctionStore[Result->Val->Integer];
|
||||
else
|
||||
IntrinsicGetLexer(&FuncLexer, Result->Val->Integer);
|
||||
|
||||
ParseType(&FuncLexer, &ReturnType); /* return type */
|
||||
TypeParse(&FuncLexer, &ReturnType); /* return type */
|
||||
Result->Typ = TypeVoid;
|
||||
LexGetPlainToken(&FuncLexer); /* function name again */
|
||||
ParseParameterList(Lexer, &FuncLexer, TRUE); /* parameters */
|
||||
|
@ -461,9 +330,8 @@ void ParseFunctionDefinition(struct LexState *Lexer, Str *Identifier, struct Lex
|
|||
ProgramFail(Lexer, "function definition expected");
|
||||
|
||||
FunctionStore[FunctionStoreUsed].End = Lexer->Pos;
|
||||
FuncValue = HeapAlloc(sizeof(struct Value) + sizeof(int));
|
||||
FuncValue = VariableAllocValueAndData(Lexer, sizeof(int));
|
||||
FuncValue->Typ = &FunctionType;
|
||||
FuncValue->Val = (union AnyValue *)((void *)FuncValue + sizeof(struct Value));
|
||||
FuncValue->Val->Integer = FunctionStoreUsed;
|
||||
FunctionStoreUsed++;
|
||||
|
||||
|
@ -486,9 +354,8 @@ void ParseMacroDefinition(struct LexState *Lexer)
|
|||
FunctionStore[FunctionStoreUsed] = *Lexer;
|
||||
LexToEndOfLine(Lexer);
|
||||
FunctionStore[FunctionStoreUsed].End = Lexer->Pos;
|
||||
MacroValue = HeapAlloc(sizeof(struct Value) + sizeof(int));
|
||||
MacroValue = VariableAllocValueAndData(Lexer, sizeof(int));
|
||||
MacroValue->Typ = &MacroType;
|
||||
MacroValue->Val = (union AnyValue *)((void *)MacroValue + sizeof(struct Value));
|
||||
MacroValue->Val->Integer = FunctionStoreUsed;
|
||||
FunctionStoreUsed++;
|
||||
|
||||
|
@ -628,7 +495,7 @@ int ParseStatement(struct LexState *Lexer, int RunIt)
|
|||
case TokenDoubleType:
|
||||
case TokenVoidType:
|
||||
*Lexer = PreState;
|
||||
ParseType(Lexer, &Typ);
|
||||
TypeParse(Lexer, &Typ);
|
||||
if (LexGetToken(Lexer, &LexerValue) != TokenIdentifier)
|
||||
ProgramFail(Lexer, "identifier expected");
|
||||
|
||||
|
@ -689,4 +556,3 @@ void Parse(const Str *FileName, const Str *Source, int RunIt)
|
|||
if (Lexer.Pos != Lexer.End)
|
||||
ProgramFail(&Lexer, "parse error");
|
||||
}
|
||||
|
||||
|
|
68
picoc.h
68
picoc.h
|
@ -10,6 +10,7 @@
|
|||
#define STACK_MAX 10 /* maximum function call stack depth */
|
||||
#define PARAMETER_MAX 10 /* maximum number of parameters to a function */
|
||||
#define LOCAL_TABLE_SIZE 11 /* maximum number of local variables */
|
||||
#define STRUCT_TABLE_SIZE 11 /* maximum number of struct/union members */
|
||||
#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,6 +38,8 @@
|
|||
|
||||
#define ISVALUETYPE(t) (((t)->Base == TypeInt) || ((t)->Base == TypeFP) || ((t)->Base == TypeString))
|
||||
|
||||
struct Table;
|
||||
|
||||
/* lexical tokens */
|
||||
enum LexToken
|
||||
{
|
||||
|
@ -84,6 +87,14 @@ enum LexToken
|
|||
TokenFloatType,
|
||||
TokenDoubleType,
|
||||
TokenVoidType,
|
||||
TokenEnumType,
|
||||
TokenLongType,
|
||||
TokenSignedType,
|
||||
TokenShortType,
|
||||
TokenStructType,
|
||||
TokenUnionType,
|
||||
TokenUnsignedType,
|
||||
TokenTypedef,
|
||||
TokenDo,
|
||||
TokenElse,
|
||||
TokenFor,
|
||||
|
@ -106,6 +117,15 @@ typedef struct _Str
|
|||
const char *Str;
|
||||
} Str;
|
||||
|
||||
/* lexer state - so we can lex nested files */
|
||||
struct LexState
|
||||
{
|
||||
int Line;
|
||||
const char *Pos;
|
||||
const char *End;
|
||||
const Str *FileName;
|
||||
};
|
||||
|
||||
/* function definition - really just where it is in the source file */
|
||||
struct FuncDef
|
||||
{
|
||||
|
@ -126,13 +146,21 @@ enum BaseType
|
|||
TypeMacro, /* a macro */
|
||||
TypePointer, /* a pointer */
|
||||
TypeArray, /* an array of a sub-type */
|
||||
TypeStruct, /* aggregate type */
|
||||
TypeUnion, /* merged type */
|
||||
TypeEnum, /* enumated integer type */
|
||||
TypeType /* a type (eg. typedef) */
|
||||
};
|
||||
|
||||
struct ValueType
|
||||
{
|
||||
enum BaseType Base; /* what kind of type this is */
|
||||
struct ValueType *SubType; /* sub-type for pointer and array types */
|
||||
int ArraySize; /* the size of an array type */
|
||||
int Sizeof; /* the storage required */
|
||||
struct ValueType *FromType; /* the type we're derived from (or NULL) */
|
||||
struct ValueType *DerivedTypeList; /* first in a list of types derived from this one */
|
||||
struct ValueType *Next; /* next item in the derived type list */
|
||||
struct Table *Members; /* members of a struct, union or enum */
|
||||
};
|
||||
|
||||
struct ArrayValue
|
||||
|
@ -159,6 +187,8 @@ union AnyValue
|
|||
Str String;
|
||||
struct ArrayValue Array;
|
||||
struct PointerValue Pointer;
|
||||
struct LexState Lexer;
|
||||
struct ValueType *Typ;
|
||||
};
|
||||
|
||||
struct Value
|
||||
|
@ -181,15 +211,6 @@ struct Table
|
|||
struct TableEntry *HashTable;
|
||||
};
|
||||
|
||||
/* lexer state - so we can lex nested files */
|
||||
struct LexState
|
||||
{
|
||||
int Line;
|
||||
const char *Pos;
|
||||
const char *End;
|
||||
const Str *FileName;
|
||||
};
|
||||
|
||||
/* stack frame for function calls */
|
||||
struct StackFrame
|
||||
{
|
||||
|
@ -199,12 +220,19 @@ struct StackFrame
|
|||
};
|
||||
|
||||
/* globals */
|
||||
struct Table GlobalTable;
|
||||
extern struct Table GlobalTable;
|
||||
extern struct LexState FunctionStore[FUNCTION_STORE_MAX];
|
||||
extern int FunctionStoreUsed;
|
||||
extern struct Value Parameter[PARAMETER_MAX];
|
||||
extern int ParameterUsed;
|
||||
extern struct Value ReturnValue;
|
||||
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;
|
||||
|
||||
/* str.c */
|
||||
void StrToC(char *Dest, int DestSize, const Str *Source);
|
||||
|
@ -235,7 +263,11 @@ void LexToEndOfLine(struct LexState *Lexer);
|
|||
/* parse.c */
|
||||
void ParseInit(void);
|
||||
void Parse(const Str *FileName, const Str *Source, int RunIt);
|
||||
int ParseType(struct LexState *Lexer, struct ValueType **Typ);
|
||||
|
||||
/* type.c */
|
||||
void TypeInit();
|
||||
int TypeSizeof(struct ValueType *Typ);
|
||||
int TypeParse(struct LexState *Lexer, struct ValueType **Typ, Str *Identifier);
|
||||
|
||||
/* intrinsic.c */
|
||||
void IntrinsicInit(struct Table *GlobalTable);
|
||||
|
@ -250,5 +282,15 @@ int HeapPopStackFrame();
|
|||
void *HeapAlloc(int Size);
|
||||
void HeapFree(void *Mem);
|
||||
|
||||
#endif /* PICOC_H */
|
||||
/* variable.c */
|
||||
void VariableInit();
|
||||
void *VariableAlloc(struct LexState *Lexer, int Size);
|
||||
struct Value *VariableAllocValueAndData(struct LexState *Lexer, int DataSize);
|
||||
struct Value *VariableAllocValueAndCopy(struct LexState *Lexer, struct Value *FromValue);
|
||||
struct Value *VariableAllocValueFromType(struct LexState *Lexer, struct ValueType *Typ);
|
||||
void VariableDefine(struct LexState *Lexer, const Str *Ident, struct Value *InitValue);
|
||||
int VariableDefined(Str *Ident);
|
||||
void VariableGet(struct LexState *Lexer, Str *Ident, struct Value *Val, struct Value **LVal);
|
||||
void VariableStackFrameAdd(struct LexState *Lexer);
|
||||
|
||||
#endif /* PICOC_H */
|
||||
|
|
34
table.c
34
table.c
|
@ -1,27 +1,16 @@
|
|||
#include <string.h>
|
||||
#include "picoc.h"
|
||||
|
||||
/* hash function */
|
||||
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;
|
||||
if (Key->Len == 0)
|
||||
return 0;
|
||||
else
|
||||
return ((*Key->Str << 24) | (Key->Str[Key->Len-1] << 16) | (Key->Str[Key->Len >> 1] << 8)) ^ Key->Len;
|
||||
}
|
||||
|
||||
/* initialise a table */
|
||||
void TableInit(struct Table *Tbl, struct TableEntry *HashTable, int Size)
|
||||
{
|
||||
Tbl->Size = Size;
|
||||
|
@ -44,6 +33,7 @@ static int TableCheckEntry(struct Table *Tbl, const Str *Key, int HashPos)
|
|||
return -2; /* wrong key */
|
||||
}
|
||||
|
||||
/* search a table for an identifier. sets AddAt to where to add it at if not found */
|
||||
static int TableSearch(struct Table *Tbl, const Str *Key, int *AddAt)
|
||||
{
|
||||
int HashValue;
|
||||
|
@ -71,6 +61,7 @@ static int TableSearch(struct Table *Tbl, const Str *Key, int *AddAt)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* set an identifier to a value. returns FALSE if it already exists */
|
||||
int TableSet(struct Table *Tbl, const Str *Key, struct Value *Val)
|
||||
{
|
||||
int HashPos;
|
||||
|
@ -88,12 +79,14 @@ int TableSet(struct Table *Tbl, const Str *Key, struct Value *Val)
|
|||
struct TableEntry *Entry = &Tbl->HashTable[AddAt];
|
||||
Entry->Key = *Key;
|
||||
Entry->Val = Val;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* find a value in a table. returns FALSE if not found */
|
||||
int TableGet(struct Table *Tbl, const Str *Key, struct Value **Val)
|
||||
{
|
||||
int HashPos;
|
||||
|
@ -107,4 +100,3 @@ int TableGet(struct Table *Tbl, const Str *Key, struct Value **Val)
|
|||
*Val = Tbl->HashTable[HashPos].Val;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
210
type.c
Normal file
210
type.c
Normal file
|
@ -0,0 +1,210 @@
|
|||
#include "picoc.h"
|
||||
|
||||
/* some basic types */
|
||||
struct ValueType UberType;
|
||||
struct ValueType IntType;
|
||||
struct ValueType CharType;
|
||||
struct ValueType StringType;
|
||||
struct ValueType FPType;
|
||||
struct ValueType VoidType;
|
||||
struct ValueType FunctionType;
|
||||
struct ValueType MacroType;
|
||||
struct ValueType EnumType;
|
||||
struct ValueType Type_Type;
|
||||
|
||||
|
||||
/* add a new type to the set of types we know about */
|
||||
struct ValueType *TypeAdd(struct LexState *Lexer, struct ValueType *ParentType, enum BaseType Base, int ArraySize, Str *Identifier, int Sizeof)
|
||||
{
|
||||
struct ValueType *NewType = VariableAlloc(sizeof(struct ValueType));
|
||||
NewType->Base = Base;
|
||||
NewType->ArraySize = ArraySize;
|
||||
NewType->Sizeof = Sizeof;
|
||||
NewType->Identifier = Identifier;
|
||||
NewType->Members = NULL;
|
||||
NewType->FromType = ParentType;
|
||||
NewType->DerivedTypeList = NULL;
|
||||
NewType->Next = ParentType->DerivedTypeList;
|
||||
ParentType->DerivedTypeList = NewType;
|
||||
|
||||
return NewType;
|
||||
}
|
||||
|
||||
/* given a parent type, get a matching derived type and make one if necessary */
|
||||
struct ValueType *TypeGetMatching(struct LexState *Lexer, struct ValueType *ParentType, enum BaseType Base, int ArraySize, Str *Identifier)
|
||||
{
|
||||
int Sizeof;
|
||||
struct ValueType *ThisType = ParentType->DerivedTypeList;
|
||||
while (ThisType != NULL && (ThisType->Base != Base || ThisType->ArraySize != ArraySize || !StrEqual(ThisType->Identifier, Identifier))
|
||||
ThisType = ThisType->Next;
|
||||
|
||||
if (ThisType != NULL)
|
||||
return ThisType;
|
||||
|
||||
switch (Base)
|
||||
{
|
||||
case TypePointer: Sizeof = sizeof(struct PointerValue); break;
|
||||
case TypeArray: Sizeof = ArraySize * ParentType->Sizeof; break;
|
||||
case TypeEnum: Sizeof = sizeof(int); break;
|
||||
default: Sizeof = 0; break; /* structs and unions will get bigger when we add members to them */
|
||||
}
|
||||
|
||||
return TypeAdd(Lexer, ParentType, Base, ArraySize, Identifier, Sizeof);
|
||||
}
|
||||
|
||||
/* add a base type */
|
||||
void TypeAddBaseType(struct ValueType *TypeNode, enum BaseType Base, int Sizeof)
|
||||
{
|
||||
TypeNode->Base = Base;
|
||||
TypeNode->ArraySize = 0;
|
||||
TypeNode->Sizeof = Sizeof;
|
||||
TypeNode->Identifier = Identifier;
|
||||
TypeNode->Members = NULL;
|
||||
TypeNode->FromType = NULL;
|
||||
TypeNode->DerivedTypeList = NULL;
|
||||
TypeNode->Next = UberType->DerivedTypeList;
|
||||
UberType->DerivedTypeList = NewType;
|
||||
}
|
||||
|
||||
/* initialise the type system */
|
||||
void TypeInit()
|
||||
{
|
||||
UberType.DerivedTypeList = NULL;
|
||||
TypeAddBaseType(&IntType, TypeInt, sizeof(int));
|
||||
TypeAddBaseType(&CharType, TypeChar, sizeof(char));
|
||||
TypeAddBaseType(&StringType, TypeString, sizeof(Str));
|
||||
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 *));
|
||||
}
|
||||
|
||||
/* parse a struct or union declaration */
|
||||
void TypeParseStruct(struct LexState *Lexer, struct ValueType **Typ, int IsStruct)
|
||||
{
|
||||
union AnyValue LexValue;
|
||||
int TotalSize = 0;
|
||||
struct ValueType *MemberType;
|
||||
Str MemberIdentifier;
|
||||
struct Value *MemberValue;
|
||||
|
||||
if (LexGetToken(Lexer, &LexValue) != TokenIdentifier)
|
||||
ProgramFail(Lexer, "struct/union name required");
|
||||
|
||||
if (LexGetTokenOnly(Lexer) != TokenOpenBrace)
|
||||
ProgramFail(Lexer, "'{' expected");
|
||||
|
||||
if (StackLevel != 0)
|
||||
ProgramFail(Lexer, "struct/union definitions can only be globals");
|
||||
|
||||
*Typ = TypeGetMatching(Lexer, &UberType, IsStruct ? TypeStruct : TypeUnion, 0, &LexValue.String);
|
||||
(*Typ)->Members = VariableAlloc(sizeof(struct Table) + STRUCT_TABLE_SIZE * sizeof(struct TableEntry));
|
||||
(*Typ)->Members->HashTable = (struct Table *)((void *)(*Typ)->Members + sizeof(struct Table));
|
||||
|
||||
do {
|
||||
TypeParse(Lexer, &MemberType, &MemberIdentifier);
|
||||
|
||||
MemberValue = VariableAllocValueAndData(Lexer, sizeof(int));
|
||||
MemberValue->MustFree = TRUE;
|
||||
MemberValue->Typ = &MemberType;
|
||||
if (IsStruct)
|
||||
{ /* allocate this member's location in the struct */
|
||||
MemberValue->Value->Integer = (*Typ)->Sizeof;
|
||||
(*Typ)->Sizeof += MemberValue->Typ->Sizeof;
|
||||
}
|
||||
else
|
||||
{ /* union members always start at 0, make sure it's big enough to hold the largest member */
|
||||
MemberValue->Value->Integer = 0;
|
||||
if (MemberValue->Typ->Sizeof > (*Typ)->Sizeof)
|
||||
(*Typ)->Sizeof = MemberValue->Typ->Sizeof;
|
||||
}
|
||||
|
||||
if (!TableSet((*Typ)->Members, &MemberIdentifier, MemberValue))
|
||||
ProgramFail(Lexer, "member '%S' already defined", &MemberIdentifier);
|
||||
|
||||
} while (LexPeekTokenOnly(Lexer) != TokenCloseBrace);
|
||||
|
||||
LexGetTokenOnly(Lexer);
|
||||
}
|
||||
|
||||
/* parse a type */
|
||||
void TypeParse(struct LexState *Lexer, struct ValueType **Typ, Str *Identifier)
|
||||
{
|
||||
struct LexState Before;
|
||||
struct LexToken Token;
|
||||
union AnyValue LexValue;
|
||||
int Done = FALSE;
|
||||
*Typ = NULL;
|
||||
|
||||
while (!Done)
|
||||
{
|
||||
Before = *Lexer;
|
||||
Token = LexGetToken(Lexer, &LexValue);
|
||||
switch (Token)
|
||||
{
|
||||
case TokenIntType: case TokenLongType: case TokenShortType: *Typ = &IntType; break;
|
||||
case TokenCharType: *Typ = &CharType; break;
|
||||
case TokenFloatType: case TokenDoubleType: *Typ = &FPType; break;
|
||||
case TokenVoidType: *Typ = &VoidType; break;
|
||||
|
||||
case TokenStructType: case TokenUnionType:
|
||||
if (*Typ != NULL)
|
||||
ProgramFail(Lexer, "bad type declaration");
|
||||
|
||||
TypeParseStruct(Lexer, Typ, Token == TokenStructType);
|
||||
break;
|
||||
|
||||
case TokenOpenBracket:
|
||||
if (*Typ != NULL)
|
||||
ProgramFail(Lexer, "bad type declaration");
|
||||
|
||||
TypeParseDeclarator(Lexer, Typ, Identifier);
|
||||
if (LexGetTokenOnly(Lexer) != TokenCloseBracket)
|
||||
ProgramFail(Lexer, "')' expected");
|
||||
break;
|
||||
|
||||
case TokenAsterisk:
|
||||
if (*Typ == NULL)
|
||||
ProgramFail(Lexer, "bad type declaration");
|
||||
|
||||
*Typ = TypeGetMatching(Lexer, *Typ, TypePointer, 0);
|
||||
break;
|
||||
|
||||
case TokenIdentifier:
|
||||
if (*Typ == NULL || Identifier->Length != 0)
|
||||
ProgramFail(Lexer, "bad type declaration");
|
||||
|
||||
*Identifier = LexValue.String;
|
||||
Done = TRUE;
|
||||
break;
|
||||
|
||||
default: *Lexer = Before; Done = TRUE; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*Typ == NULL)
|
||||
ProgramFail(Lexer, "bad type declaration");
|
||||
|
||||
if (Identifier->Length != 0)
|
||||
{ /* parse stuff after the identifier */
|
||||
Done = FALSE;
|
||||
while (!Done)
|
||||
{
|
||||
Before = *Lexer;
|
||||
switch (LexGetTokenOnly(Lexer))
|
||||
{
|
||||
case TokenOpenSquareBracket:
|
||||
if (ParseExpression(xxx)
|
||||
XXX - get a closing square bracket
|
||||
*Typ = TypeGetMatching(Lexer, *Typ, TypeArray, xxx);
|
||||
break;
|
||||
|
||||
case TokenOpenBracket:
|
||||
break; // XXX - finish this
|
||||
|
||||
default: *Lexer = Before; Done = TRUE; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
111
variable.c
Normal file
111
variable.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "picoc.h"
|
||||
|
||||
/* the table of global definitions */
|
||||
struct Table GlobalTable;
|
||||
struct TableEntry GlobalHashTable[GLOBAL_TABLE_SIZE];
|
||||
|
||||
/* the table of function definitions */
|
||||
struct LexState FunctionStore[FUNCTION_STORE_MAX];
|
||||
int FunctionStoreUsed = 0;
|
||||
|
||||
/* the stack */
|
||||
struct StackFrame Stack[STACK_MAX];
|
||||
int StackUsed = 0;
|
||||
|
||||
|
||||
/* initialise the variable system */
|
||||
void VariableInit()
|
||||
{
|
||||
TableInit(&GlobalTable, &GlobalHashTable[0], GLOBAL_TABLE_SIZE);
|
||||
}
|
||||
|
||||
/* allocate some memory, either on the heap or the stack and check if we've run out */
|
||||
void *VariableAlloc(struct LexState *Lexer, int Size)
|
||||
{
|
||||
void *NewValue;
|
||||
|
||||
if (StackUsed == 0)
|
||||
NewValue = HeapAlloc(Size);
|
||||
else
|
||||
NewValue = HeapAllocStack(Size);
|
||||
|
||||
if (NewValue == NULL)
|
||||
ProgramFail(Lexer, "out of memory");
|
||||
|
||||
return NewValue;
|
||||
}
|
||||
|
||||
/* allocate a value either on the heap or the stack using space dependent on what type we want */
|
||||
struct Value *VariableAllocValueAndData(struct LexState *Lexer, int DataSize)
|
||||
{
|
||||
struct Value *NewValue = VariableAlloc(Lexer, DataSize);
|
||||
NewValue->Val = (union AnyValue *)((void *)NewValue + sizeof(struct Value));
|
||||
NewValue->MustFree = (StackUsed == 0);
|
||||
|
||||
return NewValue;
|
||||
}
|
||||
|
||||
/* allocate a value given its type */
|
||||
struct Value *VariableAllocValueFromType(struct LexState *Lexer, struct ValueType *Typ)
|
||||
{
|
||||
struct Value *NewValue = VariableAllocValueAndData(Typ->Sizeof);
|
||||
NewValue->Typ = Typ;
|
||||
return NewValue;
|
||||
}
|
||||
|
||||
/* allocate a value either on the heap or the stack and copy its value */
|
||||
struct Value *VariableAllocValueAndCopy(struct LexState *Lexer, struct Value *FromValue)
|
||||
{
|
||||
struct Value *NewValue = VariableAllocValueAndData(TypeSizeof(FromValue->Typ));
|
||||
NewValue->Typ = FromValue->Typ;
|
||||
memcpy(NewValue->Val, FromValue->Val, TypeSizeof(FromValue->Typ));
|
||||
return NewValue;
|
||||
}
|
||||
|
||||
/* define a variable */
|
||||
void VariableDefine(struct LexState *Lexer, const Str *Ident, struct Value *InitValue)
|
||||
{
|
||||
if (!TableSet((StackUsed == 0) ? &GlobalTable : &Stack[StackUsed-1].LocalTable, Ident, VariableAllocValueAndCopy(InitValue)))
|
||||
ProgramFail(Lexer, "'%S' is already defined", Ident);
|
||||
}
|
||||
|
||||
/* check if a variable with a given name is defined */
|
||||
int VariableDefined(Str *Ident)
|
||||
{
|
||||
struct Value *FoundValue;
|
||||
|
||||
if (StackUsed == 0 || !TableGet(&Stack[StackUsed-1].LocalTable, Ident, &FoundValue))
|
||||
{
|
||||
if (!TableGet(&GlobalTable, Ident, &FoundValue))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* get the value of a variable. must be defined */
|
||||
void VariableGet(struct LexState *Lexer, Str *Ident, struct Value *Val, struct Value **LVal)
|
||||
{
|
||||
if (StackUsed == 0 || !TableGet(&Stack[StackUsed-1].LocalTable, Ident, LVal))
|
||||
{
|
||||
if (!TableGet(&GlobalTable, Ident, LVal))
|
||||
ProgramFail(Lexer, "'%S' is undefined", Ident);
|
||||
}
|
||||
|
||||
*Val = **LVal;
|
||||
}
|
||||
|
||||
/* add a stack frame when doing a function call */
|
||||
void VariableStackFrameAdd(struct LexState *Lexer)
|
||||
{
|
||||
struct StackFrame *NewFrame = &Stack[StackUsed];
|
||||
|
||||
if (StackUsed >= STACK_MAX)
|
||||
ProgramFail(Lexer, "too many nested function calls");
|
||||
|
||||
NewFrame->ReturnLex = *Lexer;
|
||||
TableInit(&NewFrame->LocalTable, &NewFrame->LocalHashTable[0], LOCAL_TABLE_SIZE);
|
||||
StackUsed++;
|
||||
}
|
Loading…
Reference in a new issue