diff --git a/lex.c b/lex.c index 127b32b..9ca632e 100644 --- a/lex.c +++ b/lex.c @@ -72,9 +72,10 @@ struct TokenLine int NumBytes; }; -struct TokenLine *InteractiveHead = NULL; -struct TokenLine *InteractiveTail = NULL; -struct TokenLine *InteractiveCurrentLine = NULL; +static struct TokenLine *InteractiveHead = NULL; +static struct TokenLine *InteractiveTail = NULL; +static struct TokenLine *InteractiveCurrentLine = NULL; +static int LexUseStatementPrompt = FALSE; /* initialise the lexer */ @@ -466,6 +467,9 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I do { /* get the next token */ + if (Parser->Pos == NULL && InteractiveHead != NULL) + Parser->Pos = InteractiveHead->Tokens; + if (Parser->FileName != StrEmpty || InteractiveHead != NULL) { /* skip leading newlines */ while ((Token = (enum LexToken)*(unsigned char *)Parser->Pos) == TokenEndOfLine) @@ -484,10 +488,13 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I if (InteractiveHead == NULL || (unsigned char *)Parser->Pos == &InteractiveTail->Tokens[InteractiveTail->NumBytes-1]) { /* get interactive input */ - if (InteractiveHead == NULL) - PlatformPrintf("picoc> "); + if (LexUseStatementPrompt) + { + PlatformPrintf(INTERACTIVE_PROMPT_STATEMENT); + LexUseStatementPrompt = FALSE; + } else - PlatformPrintf("> "); + PlatformPrintf(INTERACTIVE_PROMPT_LINE); if (PlatformGetLine(&LineBuffer[0], LINEBUFFER_MAX) == NULL) return TokenEOF; @@ -631,8 +638,43 @@ void *LexCopyTokens(struct ParseState *StartParser, struct ParseState *EndParser return NewTokens; } +/* indicate that we've completed up to this point in the interactive input and free expired tokens */ +void LexInteractiveClear(struct ParseState *Parser) +{ + while (InteractiveHead != NULL) + { + struct TokenLine *NextLine = InteractiveHead->Next; + + HeapFree(InteractiveHead->Tokens); + HeapFree(InteractiveHead); + InteractiveHead = NextLine; + } + + Parser->Pos = NULL; + InteractiveTail = NULL; +} + /* indicate that we've completed up to this point in the interactive input and free expired tokens */ void LexInteractiveCompleted(struct ParseState *Parser) { - //XXX - write this + while (InteractiveHead != NULL && !(Parser->Pos >= (void *)&InteractiveHead->Tokens[0] && Parser->Pos < (void *)&InteractiveHead->Tokens[InteractiveHead->NumBytes])) + { /* this token line is no longer needed - free it */ + struct TokenLine *NextLine = InteractiveHead->Next; + + HeapFree(InteractiveHead->Tokens); + HeapFree(InteractiveHead); + InteractiveHead = NextLine; + + if (InteractiveHead == NULL) + { /* we've emptied the list */ + Parser->Pos = NULL; + InteractiveTail = NULL; + } + } +} + +/* the next time we prompt, make it the full statement prompt */ +void LexInteractiveStatementPrompt() +{ + LexUseStatementPrompt = TRUE; } diff --git a/parse.c b/parse.c index f3b9351..4680c8d 100644 --- a/parse.c +++ b/parse.c @@ -1075,9 +1075,19 @@ void Parse(const char *FileName, const char *Source, int SourceLen, int RunIt) void ParseInteractive() { struct ParseState Parser; + int Ok; LexInitParser(&Parser, NULL, StrEmpty, 1, TRUE); - - while (ParseStatement(&Parser)) + PlatformSetExitPoint(); + LexInteractiveClear(&Parser); + + do + { + LexInteractiveStatementPrompt(); + Ok = ParseStatement(&Parser); LexInteractiveCompleted(&Parser); + + } while (Ok); + + PlatformPrintf("\n"); } diff --git a/picoc.c b/picoc.c index c9f8a73..fd2d73a 100644 --- a/picoc.c +++ b/picoc.c @@ -18,17 +18,23 @@ void Initialise() int main(int argc, char **argv) { if (argc < 2) - ProgramFail(NULL, "Format: picoc - run a program\n picoc -i - interactive mode\n"); + { + PlatformPrintf("Format: picoc - run a program\n picoc -i - interactive mode\n"); + exit(1); + } Initialise(); - if (PlatformSetExitPoint()) - return 1; if (strcmp(argv[1], "-i") == 0) ParseInteractive(); else + { + if (PlatformSetExitPoint()) + return 1; + PlatformScanFile(argv[1]); - + } + return 0; } #else diff --git a/picoc.h b/picoc.h index effc17e..a595560 100644 --- a/picoc.h +++ b/picoc.h @@ -260,7 +260,9 @@ void LexInitParser(struct ParseState *Parser, void *TokenSource, const char *Fil enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int IncPos); 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 */ int ParseExpression(struct ParseState *Parser, struct Value **Result); diff --git a/platform.h b/platform.h index 700f677..dc0f8e2 100644 --- a/platform.h +++ b/platform.h @@ -20,6 +20,9 @@ #define LOCAL_TABLE_SIZE 11 /* size of local variable table (can expand) */ #define STRUCT_TABLE_SIZE 11 /* size of struct/union member table (can expand) */ +#define INTERACTIVE_PROMPT_STATEMENT "picoc> " +#define INTERACTIVE_PROMPT_LINE "> " + /* host platform includes */ #ifdef UNIX_HOST #include @@ -31,6 +34,7 @@ #include #include #include +#include #ifndef NO_FP #include #endif diff --git a/platform_support.c b/platform_support.c index 9e09409..721832e 100644 --- a/platform_support.c +++ b/platform_support.c @@ -51,15 +51,16 @@ void PlatformScanFile(const char *FileName) } /* mark where to end the program for platforms which require this */ +static jmp_buf ExitBuf; int PlatformSetExitPoint() { - return 0; + return setjmp(ExitBuf); } /* exit the program */ void PlatformExit() { - exit(1); + longjmp(ExitBuf, 1); } #endif @@ -67,19 +68,19 @@ void PlatformExit() /* get a line of interactive input */ char *PlatformGetLine(char *Buf, int MaxLen) { - return NULL; + return NULL; } /* write a character to the console */ void PlatformPutc(unsigned char OutCh) { - putchar(OutCh); + putchar(OutCh); } /* mark where to end the program for platforms which require this */ int PlatformSetExitPoint() { - return 0; + return 0; } /* exit the program */ @@ -87,8 +88,8 @@ extern int errjmp[]; void PlatformExit() { - errjmp[40] = 1; - longjmp(errjmp, 1); + errjmp[40] = 1; + longjmp(errjmp, 1); } #endif