#ifndef INTERPRETER_H #define INTERPRETER_H #include "platform.h" /* 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 #define MEM_ALIGN(x) (((x) + sizeof(ALIGN_TYPE) - 1) & ~(sizeof(ALIGN_TYPE)-1)) #define GETS_BUF_MAX 256 /* small processors use a simplified FILE * for stdio, otherwise use the system FILE * */ #ifdef BUILTIN_MINI_STDLIB typedef struct OutputStream IOFILE; #else typedef FILE IOFILE; #endif /* coercion of numeric types to other numeric types */ #ifndef NO_FP #define IS_FP(v) ((v)->Typ->Base == TypeFP) #define FP_VAL(v) ((v)->Val->FP) #else #define IS_FP(v) 0 #define FP_VAL(v) 0 #endif #define IS_POINTER_COERCIBLE(v, ap) ((ap) ? ((v)->Typ->Base == TypePointer) : 0) #define POINTER_COERCE(v) ((int)(v)->Val->Pointer) #define IS_INTEGER_NUMERIC_TYPE(t) ((t)->Base >= TypeInt && (t)->Base <= TypeUnsignedLong) #define IS_INTEGER_NUMERIC(v) IS_INTEGER_NUMERIC_TYPE((v)->Typ) #define IS_NUMERIC_COERCIBLE(v) (IS_INTEGER_NUMERIC(v) || IS_FP(v)) #define IS_NUMERIC_COERCIBLE_PLUS_POINTERS(v,ap) (IS_NUMERIC_COERCIBLE(v) || IS_POINTER_COERCIBLE(v,ap)) struct Table; /* lexical tokens */ enum LexToken { /* 0x00 */ TokenNone, /* 0x01 */ TokenComma, /* 0x02 */ TokenAssign, TokenAddAssign, TokenSubtractAssign, TokenMultiplyAssign, TokenDivideAssign, TokenModulusAssign, /* 0x08 */ TokenShiftLeftAssign, TokenShiftRightAssign, TokenArithmeticAndAssign, TokenArithmeticOrAssign, TokenArithmeticExorAssign, /* 0x0d */ TokenQuestionMark, TokenColon, /* 0x0f */ TokenLogicalOr, /* 0x10 */ TokenLogicalAnd, /* 0x11 */ TokenArithmeticOr, /* 0x12 */ TokenArithmeticExor, /* 0x13 */ TokenAmpersand, /* 0x14 */ TokenEqual, TokenNotEqual, /* 0x16 */ TokenLessThan, TokenGreaterThan, TokenLessEqual, TokenGreaterEqual, /* 0x1a */ TokenShiftLeft, TokenShiftRight, /* 0x1c */ TokenPlus, TokenMinus, /* 0x1e */ TokenAsterisk, TokenSlash, TokenModulus, /* 0x21 */ TokenIncrement, TokenDecrement, TokenUnaryNot, TokenUnaryExor, TokenSizeof, TokenCast, /* 0x27 */ TokenLeftSquareBracket, TokenRightSquareBracket, TokenDot, TokenArrow, /* 0x2b */ TokenOpenBracket, TokenCloseBracket, /* 0x2d */ TokenIdentifier, TokenIntegerConstant, TokenFPConstant, TokenStringConstant, TokenCharacterConstant, /* 0x32 */ TokenSemicolon, TokenEllipsis, /* 0x34 */ TokenLeftBrace, TokenRightBrace, /* 0x36 */ TokenIntType, TokenCharType, TokenFloatType, TokenDoubleType, TokenVoidType, TokenEnumType, /* 0x3c */ TokenLongType, TokenSignedType, TokenShortType, TokenStaticType, TokenAutoType, TokenRegisterType, TokenExternType, TokenStructType, TokenUnionType, TokenUnsignedType, TokenTypedef, /* 0x46 */ TokenContinue, TokenDo, TokenElse, TokenFor, TokenIf, TokenWhile, TokenBreak, TokenSwitch, TokenCase, TokenDefault, TokenReturn, /* 0x51 */ TokenHashDefine, TokenHashInclude, TokenHashIf, TokenHashIfdef, TokenHashIfndef, TokenHashElse, TokenHashEndif, /* 0x58 */ TokenNew, TokenDelete, /* 0x5a */ TokenOpenMacroBracket, /* 0x5b */ TokenEOF, TokenEndOfLine, TokenEndOfFunction }; /* used in dynamic memory allocation */ struct AllocNode { unsigned int Size; struct AllocNode *NextFree; }; /* whether we're running or skipping code */ enum RunMode { RunModeRun, /* we're running code as we parse it */ RunModeSkip, /* skipping code, not running */ RunModeReturn, /* returning from a function */ RunModeCaseSearch, /* searching for a case label */ RunModeBreak, /* breaking out of a switch/while/do */ RunModeContinue /* as above but repeat the loop */ }; /* parser state - has all this detail so we can parse nested files */ struct ParseState { const unsigned char *Pos; const char *FileName; short int Line; short int CharacterPos; enum RunMode Mode; /* whether to skip or run code */ int SearchLabel; /* what case label we're searching for */ short int HashIfLevel; short int HashIfEvaluateToLevel; const char *SourceText; }; /* values */ enum BaseType { TypeVoid, /* no type */ TypeInt, /* integer */ TypeShort, /* short integer */ TypeChar, /* a single character (unsigned) */ TypeLong, /* long integer */ TypeUnsignedInt, /* unsigned integer */ TypeUnsignedShort, /* unsigned short integer */ TypeUnsignedLong, /* unsigned long integer */ #ifndef NO_FP TypeFP, /* floating point */ #endif TypeFunction, /* a function */ TypeMacro, /* a macro */ TypePointer, /* a pointer */ TypeArray, /* an array of a sub-type */ TypeStruct, /* aggregate type */ TypeUnion, /* merged type */ TypeEnum, /* enumerated integer type */ Type_Type /* a type for storing types */ }; /* data type */ struct ValueType { enum BaseType Base; /* what kind of type this is */ int ArraySize; /* the size of an array type */ int Sizeof; /* the storage required */ int AlignBytes; /* the alignment boundary of this type */ const char *Identifier; /* the name of a struct or union */ 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 or union */ int OnHeap; /* true if allocated on the heap */ int StaticQualifier; /* true if it's a static */ }; /* function definition */ struct FuncDef { struct ValueType *ReturnType; /* the return value type */ int NumParams; /* the number of parameters */ int VarArgs; /* has a variable number of arguments after the explicitly specified ones */ struct ValueType **ParamType; /* array of parameter types */ char **ParamName; /* array of parameter names */ void (*Intrinsic)(); /* intrinsic call address or NULL */ struct ParseState Body; /* lexical tokens of the function body if not intrinsic */ }; /* macro definition */ struct MacroDef { int NumParams; /* the number of parameters */ char **ParamName; /* array of parameter names */ struct ParseState Body; /* lexical tokens of the function body if not intrinsic */ }; /* values */ union AnyValue { unsigned char Character; short ShortInteger; int Integer; long LongInteger; unsigned short UnsignedShortInteger; unsigned int UnsignedInteger; unsigned long UnsignedLongInteger; char *Identifier; char ArrayMem[2]; /* placeholder for where the data starts, doesn't point to it */ struct ValueType *Typ; struct FuncDef FuncDef; struct MacroDef MacroDef; #ifndef NO_FP double FP; #endif void *Pointer; /* unsafe native pointers */ }; struct Value { struct ValueType *Typ; /* the type of this value */ union AnyValue *Val; /* pointer to the AnyValue which holds the actual content */ struct Value *LValueFrom; /* if an LValue, this is a Value our LValue is contained within (or NULL) */ char ValOnHeap; /* the AnyValue is on the heap (but this Value is on the stack) */ char ValOnStack; /* the AnyValue is on the stack along with this Value */ char IsLValue; /* is modifiable and is allocated somewhere we can usefully modify it */ }; /* hash table data structure */ struct TableEntry { struct TableEntry *Next; /* next item in this hash chain */ const char *DeclFileName; /* where the variable was declared */ unsigned short DeclLine; unsigned short DeclColumn; union TableEntryPayload { struct ValueEntry { char *Key; /* points to the shared string table */ struct Value *Val; /* the value we're storing */ } v; /* used for tables of values */ char Key[1]; /* dummy size - used for the shared string table */ } p; }; struct Table { short Size; short OnHeap; struct TableEntry **HashTable; }; /* stack frame for function calls */ struct StackFrame { struct ParseState ReturnParser; /* how we got here */ const char *FuncName; /* the name of the function we're in */ struct Value *ReturnValue; /* copy the return value here */ struct Value **Parameter; /* array of parameter values */ int NumParams; /* the number of parameters */ struct Table LocalTable; /* the local variables and parameters */ struct TableEntry *LocalHashTable[LOCAL_TABLE_SIZE]; struct StackFrame *PreviousStackFrame; /* the next lower stack frame */ }; /* lexer state */ enum LexMode { LexModeNormal, LexModeHashInclude, LexModeHashDefine, LexModeHashDefineSpace, LexModeHashDefineSpaceIdent }; struct LexState { const char *Pos; const char *End; const char *FileName; int Line; int CharacterPos; const char *SourceText; enum LexMode Mode; int EmitExtraNewlines; }; /* library function definition */ struct LibraryFunction { void (*Func)(struct ParseState *Parser, struct Value *, struct Value **, int); const char *Prototype; }; /* output stream-type specific state information */ union OutputStreamInfo { struct StringOutputStream { struct ParseState *Parser; char *WritePos; } Str; }; /* stream-specific method for writing characters to the console */ typedef void CharWriter(unsigned char, union OutputStreamInfo *); /* used when writing output to a string - eg. sprintf() */ struct OutputStream { CharWriter *Putch; union OutputStreamInfo i; }; /* possible results of parsing a statement */ enum ParseResult { ParseResultEOF, ParseResultError, ParseResultOk }; /* globals */ extern void *HeapStackTop; extern struct Table GlobalTable; extern struct StackFrame *TopStackFrame; extern struct ValueType UberType; extern struct ValueType IntType; extern struct ValueType CharType; #ifndef NO_FP extern struct ValueType FPType; #endif extern struct ValueType VoidType; extern struct ValueType TypeType; extern struct ValueType FunctionType; extern struct ValueType MacroType; extern struct ValueType *CharPtrType; extern struct ValueType *CharPtrPtrType; extern struct ValueType *CharArrayType; extern struct ValueType *VoidPtrType; extern char *StrEmpty; extern struct PointerValue NULLPointer; extern struct LibraryFunction CLibrary[]; extern struct LibraryFunction PlatformLibrary[]; extern IOFILE *CStdOut; /* table.c */ 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, const char *DeclFileName, int DeclLine, int DeclColumn); int TableGet(struct Table *Tbl, const char *Key, struct Value **Val, const char **DeclFileName, int *DeclLine, int *DeclColumn); struct Value *TableDelete(struct Table *Tbl, const char *Key); char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen); void TableStrFree(); /* lex.c */ void LexInit(); void LexCleanup(); void *LexAnalyse(const char *FileName, const char *Source, int SourceLen, int *TokenLen); void LexInitParser(struct ParseState *Parser, const char *SourceText, void *TokenSource, const char *FileName, int RunIt); enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int IncPos); enum LexToken LexRawPeekToken(struct ParseState *Parser); void LexToEndOfLine(struct ParseState *Parser); void *LexCopyTokens(struct ParseState *StartParser, struct ParseState *EndParser); void LexInteractiveClear(struct ParseState *Parser); void LexInteractiveCompleted(struct ParseState *Parser); void LexInteractiveStatementPrompt(); /* parse.c */ /* the following are defined in picoc.h: * void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource); * void PicocParseInteractive(); */ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemicolon); struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, char *Identifier); void ParseCleanup(); void ParserCopyPos(struct ParseState *To, struct ParseState *From); void ParserCopy(struct ParseState *To, struct ParseState *From); /* expression.c */ int ExpressionParse(struct ParseState *Parser, struct Value **Result); long ExpressionParseInt(struct ParseState *Parser); void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct Value *SourceValue, int Force, const char *FuncName, int ParamNo, int AllowPointerCoercion); long ExpressionCoerceInteger(struct Value *Val); unsigned long ExpressionCoerceUnsignedInteger(struct Value *Val); #ifndef NO_FP double ExpressionCoerceFP(struct Value *Val); #endif /* type.c */ void TypeInit(); void TypeCleanup(); int TypeSize(struct ValueType *Typ, int ArraySize, int Compact); int TypeSizeValue(struct Value *Val, int Compact); int TypeStackSizeValue(struct Value *Val); int TypeLastAccessibleOffset(struct Value *Val); int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ, int *IsStatic); void TypeParseIdentPart(struct ParseState *Parser, struct ValueType *BasicTyp, struct ValueType **Typ, char **Identifier); void TypeParse(struct ParseState *Parser, struct ValueType **Typ, char **Identifier, int *IsStatic); struct ValueType *TypeGetMatching(struct ParseState *Parser, struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier, int AllowDuplicates); struct ValueType *TypeCreateOpaqueStruct(struct ParseState *Parser, const char *StructName, int Size); /* heap.c */ void HeapInit(int StackSize); void HeapCleanup(); void *HeapAllocStack(int Size); int HeapPopStack(void *Addr, int Size); void HeapUnpopStack(int Size); void HeapPushStackFrame(); int HeapPopStackFrame(); void *HeapAllocMem(int Size); void HeapFreeMem(void *Mem); /* variable.c */ void VariableInit(); void VariableCleanup(); void VariableFree(struct Value *Val); void VariableTableCleanup(struct Table *HashTable); void *VariableAlloc(struct ParseState *Parser, int Size, int OnHeap); void VariableStackPop(struct ParseState *Parser, struct Value *Var); struct Value *VariableAllocValueAndData(struct ParseState *Parser, int DataSize, int IsLValue, struct Value *LValueFrom, int OnHeap); struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value *FromValue, int OnHeap); struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue, struct Value *LValueFrom, int OnHeap); struct Value *VariableAllocValueFromExistingData(struct ParseState *Parser, struct ValueType *Typ, union AnyValue *FromValue, int IsLValue, struct Value *LValueFrom); struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value *FromValue); struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable); struct Value *VariableDefineButIgnoreIdentical(struct ParseState *Parser, char *Ident, struct ValueType *Typ, int IsStatic, int *FirstVisit); int VariableDefined(const char *Ident); void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal); void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct ValueType *Typ, union AnyValue *FromValue, int IsWritable); void VariableStackFrameAdd(struct ParseState *Parser, const char *FuncName, int NumParams); void VariableStackFramePop(struct ParseState *Parser); struct Value *VariableStringLiteralGet(char *Ident); void VariableStringLiteralDefine(char *Ident, struct Value *Val); void *VariableDereferencePointer(struct ParseState *Parser, struct Value *PointerValue, struct Value **DerefVal, int *DerefOffset, struct ValueType **DerefType, int *DerefIsLValue); /* clibrary.c */ void BasicIOInit(); void LibraryInit(); void LibraryAdd(struct Table *GlobalTable, const char *LibraryName, struct LibraryFunction *FuncList); void CLibraryInit(); void PrintCh(char OutCh, IOFILE *Stream); void PrintSimpleInt(long Num, IOFILE *Stream); void PrintInt(long Num, int FieldWidth, int ZeroPad, int LeftJustify, IOFILE *Stream); void PrintStr(const char *Str, IOFILE *Stream); void PrintFP(double Num, IOFILE *Stream); void PrintType(struct ValueType *Typ, IOFILE *Stream); void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs); /* platform.c */ /* the following are defined in picoc.h: * void PicocCallMain(int argc, char **argv); * int PicocPlatformSetExitPoint(); * void PicocInitialise(int StackSize); * void PicocCleanup(); * void PicocPlatformScanFile(const char *FileName); * extern int PicocExitValue; */ void ProgramFail(struct ParseState *Parser, const char *Message, ...); void AssignFail(struct ParseState *Parser, const char *Format, struct ValueType *Type1, struct ValueType *Type2, int Num1, int Num2, const char *FuncName, int ParamNo); void LexFail(struct LexState *Lexer, const char *Message, ...); void PlatformCleanup(); char *PlatformGetLine(char *Buf, int MaxLen, const char *Prompt); int PlatformGetCharacter(); void PlatformPutc(unsigned char OutCh, union OutputStreamInfo *); void PlatformErrorPrefix(struct ParseState *Parser); void PlatformPrintf(const char *Format, ...); void PlatformVPrintf(const char *Format, va_list Args); void PlatformExit(int ExitVal); char *PlatformMakeTempName(char *TempNameBuffer); void PlatformLibraryInit(); /* include.c */ void IncludeInit(); void IncludeCleanup(); void IncludeRegister(const char *IncludeName, void (*SetupFunction)(void), struct LibraryFunction *FuncList, const char *SetupCSource); void IncludeFile(char *Filename); /* the following is defined in picoc.h: * void PicocIncludeAllSystemHeaders(); */ /* stdio.c */ extern const char StdioDefs[]; extern struct LibraryFunction StdioFunctions[]; void StdioSetupFunc(void); /* math.c */ extern struct LibraryFunction MathFunctions[]; void MathSetupFunc(void); /* string.c */ extern struct LibraryFunction StringFunctions[]; void StringSetupFunc(void); /* stdlib.c */ extern struct LibraryFunction StdlibFunctions[]; void StdlibSetupFunc(void); /* time.c */ extern const char StdTimeDefs[]; extern struct LibraryFunction StdTimeFunctions[]; void StdTimeSetupFunc(void); /* errno.c */ void StdErrnoSetupFunc(void); /* ctype.c */ extern struct LibraryFunction StdCtypeFunctions[]; /* stdbool.c */ extern const char StdboolDefs[]; void StdboolSetupFunc(void); /* unistd.c */ extern const char UnistdDefs[]; extern struct LibraryFunction UnistdFunctions[]; void UnistdSetupFunc(void); #endif /* INTERPRETER_H */