picoc/platform.c
2015-06-17 16:34:26 -05:00

276 lines
8.2 KiB
C

/* 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"
static void PrintSourceTextErrorLine(IOFILE *Stream, const char *FileName,
const char *SourceText, int Line, int CharacterPos);
#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);
}