/* picoc's interface to the underlying platform. most platform-specific code * is in platform/platform_XX.c and platform/library_XX.c */ #include "picoc.h" #include "interpreter.h" #ifdef DEBUGGER static int gEnableDebugger = true; #else static int gEnableDebugger = false; #endif /* initialise everything */ void PicocInitialise(Picoc *pc, int StackSize) { memset(pc, '\0', sizeof(*pc)); PlatformInit(pc); BasicIOInit(pc); HeapInit(pc, StackSize); TableInit(pc); VariableInit(pc); LexInit(pc); TypeInit(pc); IncludeInit(pc); LibraryInit(pc); PlatformLibraryInit(pc); #ifdef DEBUGGER DebugInit(pc); #endif } /* free memory */ void PicocCleanup(Picoc *pc) { #ifdef DEBUGGER DebugCleanup(pc); #endif IncludeCleanup(pc); ParseCleanup(pc); LexCleanup(pc); VariableCleanup(pc); TypeCleanup(pc); TableStrFree(pc); HeapCleanup(pc); PlatformCleanup(pc); } /* platform-dependent code for running programs */ #if defined(UNIX_HOST) || defined(WIN32) #define CALL_MAIN_NO_ARGS_RETURN_VOID "main();" #define CALL_MAIN_WITH_ARGS_RETURN_VOID "main(__argc,__argv);" #define CALL_MAIN_NO_ARGS_RETURN_INT "__exit_value = main();" #define CALL_MAIN_WITH_ARGS_RETURN_INT "__exit_value = main(__argc,__argv);" void PicocCallMain(Picoc *pc, int argc, char **argv) { /* check if the program wants arguments */ struct Value *FuncValue = NULL; if (!VariableDefined(pc, TableStrRegister(pc, "main"))) ProgramFailNoParser(pc, "main() is not defined"); VariableGet(pc, NULL, TableStrRegister(pc, "main"), &FuncValue); if (FuncValue->Typ->Base != TypeFunction) ProgramFailNoParser(pc, "main is not a function - can't call it"); if (FuncValue->Val->FuncDef.NumParams != 0) { /* define the arguments */ VariableDefinePlatformVar(pc, NULL, "__argc", &pc->IntType, (union AnyValue *)&argc, false); VariableDefinePlatformVar(pc, NULL, "__argv", pc->CharPtrPtrType, (union AnyValue *)&argv, false); } if (FuncValue->Val->FuncDef.ReturnType == &pc->VoidType) { if (FuncValue->Val->FuncDef.NumParams == 0) PicocParse(pc, "startup", CALL_MAIN_NO_ARGS_RETURN_VOID, strlen(CALL_MAIN_NO_ARGS_RETURN_VOID), true, true, false, gEnableDebugger); else PicocParse(pc, "startup", CALL_MAIN_WITH_ARGS_RETURN_VOID, strlen(CALL_MAIN_WITH_ARGS_RETURN_VOID), true, true, false, gEnableDebugger); } else { VariableDefinePlatformVar(pc, NULL, "__exit_value", &pc->IntType, (union AnyValue *)&pc->PicocExitValue, true); if (FuncValue->Val->FuncDef.NumParams == 0) PicocParse(pc, "startup", CALL_MAIN_NO_ARGS_RETURN_INT, strlen(CALL_MAIN_NO_ARGS_RETURN_INT), true, true, false, gEnableDebugger); else PicocParse(pc, "startup", CALL_MAIN_WITH_ARGS_RETURN_INT, strlen(CALL_MAIN_WITH_ARGS_RETURN_INT), true, true, false, gEnableDebugger); } } #endif void PrintSourceTextErrorLine(IOFILE *Stream, const char *FileName, const char *SourceText, int Line, int CharacterPos) { int LineCount; int CCount; const char *LinePos; const char *CPos; if (SourceText != NULL) { /* find the source line */ for (LinePos = SourceText, LineCount = 1; *LinePos != '\0' && LineCount < Line; LinePos++) { if (*LinePos == '\n') LineCount++; } /* display the line */ for (CPos = LinePos; *CPos != '\n' && *CPos != '\0'; CPos++) PrintCh(*CPos, Stream); PrintCh('\n', Stream); /* display the error position */ for (CPos = LinePos, CCount = 0; *CPos != '\n' && *CPos != '\0' && (CCount < CharacterPos || *CPos == ' '); CPos++, CCount++) { if (*CPos == '\t') PrintCh('\t', Stream); else PrintCh(' ', Stream); } } else { /* assume we're in interactive mode - try to make the arrow match up with the input text */ for (CCount = 0; CCount < CharacterPos+(int)strlen(INTERACTIVE_PROMPT_STATEMENT); CCount++) PrintCh(' ', Stream); } PlatformPrintf(Stream, "^\n%s:%d:%d ", FileName, Line, CharacterPos); } /* exit with a message */ void ProgramFail(struct ParseState *Parser, const char *Message, ...) { va_list Args; PrintSourceTextErrorLine(Parser->pc->CStdOut, Parser->FileName, Parser->SourceText, Parser->Line, Parser->CharacterPos); va_start(Args, Message); PlatformVPrintf(Parser->pc->CStdOut, Message, Args); va_end(Args); PlatformPrintf(Parser->pc->CStdOut, "\n"); PlatformExit(Parser->pc, 1); } /* exit with a message, when we're not parsing a program */ void ProgramFailNoParser(Picoc *pc, const char *Message, ...) { va_list Args; va_start(Args, Message); PlatformVPrintf(pc->CStdOut, Message, Args); va_end(Args); PlatformPrintf(pc->CStdOut, "\n"); PlatformExit(pc, 1); } /* like ProgramFail() but gives descriptive error messages for assignment */ void AssignFail(struct ParseState *Parser, const char *Format, struct ValueType *Type1, struct ValueType *Type2, int Num1, int Num2, const char *FuncName, int ParamNo) { IOFILE *Stream = Parser->pc->CStdOut; PrintSourceTextErrorLine(Parser->pc->CStdOut, Parser->FileName, Parser->SourceText, Parser->Line, Parser->CharacterPos); PlatformPrintf(Stream, "can't %s ", (FuncName == NULL) ? "assign" : "set"); if (Type1 != NULL) PlatformPrintf(Stream, Format, Type1, Type2); else PlatformPrintf(Stream, Format, Num1, Num2); if (FuncName != NULL) PlatformPrintf(Stream, " in argument %d of call to %s()", ParamNo, FuncName); PlatformPrintf(Stream, "\n"); PlatformExit(Parser->pc, 1); } /* exit lexing with a message */ void LexFail(Picoc *pc, struct LexState *Lexer, const char *Message, ...) { va_list Args; PrintSourceTextErrorLine(pc->CStdOut, Lexer->FileName, Lexer->SourceText, Lexer->Line, Lexer->CharacterPos); va_start(Args, Message); PlatformVPrintf(pc->CStdOut, Message, Args); va_end(Args); PlatformPrintf(pc->CStdOut, "\n"); PlatformExit(pc, 1); } /* printf for compiler error reporting */ void PlatformPrintf(IOFILE *Stream, const char *Format, ...) { va_list Args; va_start(Args, Format); PlatformVPrintf(Stream, Format, Args); va_end(Args); } void PlatformVPrintf(IOFILE *Stream, const char *Format, va_list Args) { const char *FPos; for (FPos = Format; *FPos != '\0'; FPos++) { if (*FPos == '%') { FPos++; switch (*FPos) { case 's': PrintStr(va_arg(Args, char *), Stream); break; case 'd': PrintSimpleInt(va_arg(Args, int), Stream); break; case 'c': PrintCh(va_arg(Args, int), Stream); break; case 't': PrintType(va_arg(Args, struct ValueType *), Stream); break; case 'f': PrintFP(va_arg(Args, double), Stream); break; case '%': PrintCh('%', Stream); break; case '\0': FPos--; break; default: break; } } else PrintCh(*FPos, Stream); } } /* make a new temporary name. takes a static buffer of char [7] as a parameter. * should be initialised to "XX0000" * where XX can be any characters */ char *PlatformMakeTempName(Picoc *pc, char *TempNameBuffer) { int CPos = 5; while (CPos > 1) { if (TempNameBuffer[CPos] < '9') { TempNameBuffer[CPos]++; return TableStrRegister(pc, TempNameBuffer); } else { TempNameBuffer[CPos] = '0'; CPos--; } } return TableStrRegister(pc, TempNameBuffer); }