From 3a1e39f9d3517dd4f0776751583ff2092d278c0b Mon Sep 17 00:00:00 2001 From: "zik.saleeba" Date: Thu, 4 Jun 2009 07:41:06 +0000 Subject: [PATCH] New fancy error reporting feature makes nice error messages git-svn-id: http://picoc.googlecode.com/svn/trunk@330 21eae674-98b7-11dd-bd71-f92a316d2d60 --- Makefile | 4 +- clibrary.c | 2 +- expression.c | 24 +++------ lex.c | 134 +++++++++++++++++++++++++++++++-------------------- parse.c | 7 ++- picoc.h | 14 +++++- platform.c | 76 ++++++++++++++++++++++++++++- platform.h | 2 + 8 files changed, 188 insertions(+), 75 deletions(-) diff --git a/Makefile b/Makefile index 5a00203..d4a6bb2 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-Wall -pedantic -g -DUNIX_HOST #-DDEBUG_HEAP #-DDEBUG_EXPRESSIONS #-DDEBUG_LEXER +CFLAGS=-Wall -pedantic -g -DUNIX_HOST LIBS=#-lm TARGET = picoc @@ -18,7 +18,7 @@ clean: rm -f $(TARGET) $(OBJS) *~ count: - cat picoc.h picoc.c table.c lex.c parse.c expression.c heap.c type.c variable.c | grep -v '^[ ]*/\*' | grep -v '^[ ]*$$' | wc + cat picoc.h picoc.c table.c lex.c parse.c expression.c platform.c heap.c type.c variable.c | grep -v '^[ ]*/\*' | grep -v '^[ ]*$$' | wc depend: $(CC) -MM $(SRCS) >.depend diff --git a/clibrary.c b/clibrary.c index 48d672d..54f7acd 100644 --- a/clibrary.c +++ b/clibrary.c @@ -21,7 +21,7 @@ void LibraryInit(struct Table *GlobalTable, const char *LibraryName, struct Libr for (Count = 0; (*FuncList)[Count].Prototype != NULL; Count++) { Tokens = LexAnalyse(IntrinsicName, (*FuncList)[Count].Prototype, strlen((char *)(*FuncList)[Count].Prototype), NULL); - LexInitParser(&Parser, Tokens, IntrinsicName, Count+1, TRUE); + LexInitParser(&Parser, (*FuncList)[Count].Prototype, Tokens, IntrinsicName, TRUE); TypeParse(&Parser, &ReturnType, &Identifier); NewValue = ParseFunctionDefinition(&Parser, ReturnType, Identifier, TRUE); NewValue->Val->FuncDef.Intrinsic = (*FuncList)[Count].Func; diff --git a/expression.c b/expression.c index 8d875f1..4ce84a1 100644 --- a/expression.c +++ b/expression.c @@ -163,6 +163,10 @@ void ExpressionStackPushValueNode(struct ParseState *Parser, struct ExpressionSt StackNode->Next = *StackTop; StackNode->p.Val = ValueLoc; *StackTop = StackNode; +#ifdef FANCY_ERROR_MESSAGES + StackNode->Line = Parser->Line; + StackNode->CharacterPos = Parser->CharacterPos; +#endif #ifdef DEBUG_EXPRESSIONS ExpressionStackShow(*StackTop); #endif @@ -217,22 +221,6 @@ void ExpressionPushFP(struct ParseState *Parser, struct ExpressionStack **StackT } #endif -/* 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) -{ - PlatformPrintf("%s:%d: can't %s ", Parser->FileName, Parser->Line, (FuncName == NULL) ? "assign" : "set"); - - if (Type1 != NULL) - PlatformPrintf(Format, Type1, Type2); - else - PlatformPrintf(Format, Num1, Num2); - - if (FuncName != NULL) - PlatformPrintf(" in argument %d of call to %s()", ParamNo, FuncName); - - ProgramFail(NULL, ""); -} - /* assign to a pointer, leaving a value on the expression stack */ void ExpressionAssignToPointer(struct ParseState *Parser, struct Value *ToValue, struct Value *FromValue, const char *FuncName, int ParamNo) { @@ -876,6 +864,10 @@ void ExpressionStackPushOperator(struct ParseState *Parser, struct ExpressionSta StackNode->Precedence = Precedence; *StackTop = StackNode; debugf("ExpressionStackPushOperator()\n"); +#ifdef FANCY_ERROR_MESSAGES + StackNode->Line = Parser->Line; + StackNode->CharacterPos = Parser->CharacterPos; +#endif #ifdef DEBUG_EXPRESSIONS ExpressionStackShow(*StackTop); #endif diff --git a/lex.c b/lex.c index 4142f38..9b00fee 100644 --- a/lex.c +++ b/lex.c @@ -13,11 +13,21 @@ #define IS_BASE_DIGIT(c,b) (((c) >= '0' && (c) < '0' + (((b)<10)?(b):10)) || (((b) > 10) ? IS_HEX_ALPHA_DIGIT(c) : FALSE)) #define GET_BASE_DIGIT(c) (((c) <= '9') ? ((c) - '0') : (((c) <= 'F') ? ((c) - 'A' + 10) : ((c) - 'a' + 10))) -#define NEXTIS(c,x,y) { if (NextChar == (c)) { Lexer->Pos++; GotToken = (x); } else GotToken = (y); } -#define NEXTIS3(c,x,d,y,z) { if (NextChar == (c)) { Lexer->Pos++; GotToken = (x); } else NEXTIS(d,y,z) } -#define NEXTIS4(c,x,d,y,e,z,a) { if (NextChar == (c)) { Lexer->Pos++; GotToken = (x); } else NEXTIS3(d,y,e,z,a) } -#define NEXTIS3PLUS(c,x,d,y,e,z,a) { if (NextChar == (c)) { Lexer->Pos++; GotToken = (x); } else if (NextChar == (d)) { if (Lexer->Pos[1] == (e)) { Lexer->Pos += 2; GotToken = (z); } else { Lexer->Pos++; GotToken = (y); } } else GotToken = (a); } -#define NEXTISEXACTLY3(c,d,y,z) { if (NextChar == (c) && Lexer->Pos[1] == (d)) { Lexer->Pos += 2; GotToken = (y); } else GotToken = (z); } +#define NEXTIS(c,x,y) { if (NextChar == (c)) { LEXER_INC(Lexer); GotToken = (x); } else GotToken = (y); } +#define NEXTIS3(c,x,d,y,z) { if (NextChar == (c)) { LEXER_INC(Lexer); GotToken = (x); } else NEXTIS(d,y,z) } +#define NEXTIS4(c,x,d,y,e,z,a) { if (NextChar == (c)) { LEXER_INC(Lexer); GotToken = (x); } else NEXTIS3(d,y,e,z,a) } +#define NEXTIS3PLUS(c,x,d,y,e,z,a) { if (NextChar == (c)) { LEXER_INC(Lexer); GotToken = (x); } else if (NextChar == (d)) { if (Lexer->Pos[1] == (e)) { LEXER_INCN(Lexer, 2); GotToken = (z); } else { LEXER_INC(Lexer); GotToken = (y); } } else GotToken = (a); } +#define NEXTISEXACTLY3(c,d,y,z) { if (NextChar == (c) && Lexer->Pos[1] == (d)) { LEXER_INCN(Lexer, 2); GotToken = (y); } else GotToken = (z); } + +#ifdef FANCY_ERROR_REPORTING +#define LEXER_INC(l) ( (l)->Pos++, (l)->CharacterPos++ ) +#define LEXER_INCN(l, n) ( (l)->Pos+=(n), (l)->CharacterPos+=(n) ) +#define TOKEN_DATA_OFFSET 2 +#else +#define LEXER_INC(l) (l)->Pos++ +#define LEXER_INCN(l, n) (l)->Pos+=(n) +#define TOKEN_DATA_OFFSET 1 +#endif #define MAX_CHAR_VALUE 255 /* maximum value which can be represented by a "char" data type */ @@ -110,19 +120,6 @@ enum LexToken LexCheckReservedWord(const char *Word) return TokenNone; } -int IsBaseDigit(unsigned char c, int b) -{ - if (c >= '0' && c < '0' + b) - return TRUE; - else - { - if (b > 10) - return IS_HEX_ALPHA_DIGIT(c); - } - - return FALSE; -} - /* get a numeric literal - used while scanning */ enum LexToken LexGetNumber(struct LexState *Lexer, struct Value *Value) { @@ -137,20 +134,20 @@ enum LexToken LexGetNumber(struct LexState *Lexer, struct Value *Value) if (*Lexer->Pos == '0') { /* a binary, octal or hex literal */ - Lexer->Pos++; + LEXER_INC(Lexer); if (Lexer->Pos != Lexer->End) { if (*Lexer->Pos == 'x' || *Lexer->Pos == 'X') - { Base = 16; Lexer->Pos++; } + { Base = 16; LEXER_INC(Lexer); } else if (*Lexer->Pos == 'b' || *Lexer->Pos == 'B') - { Base = 2; Lexer->Pos++; } + { Base = 2; LEXER_INC(Lexer); } else if (*Lexer->Pos != '.') Base = 8; } } /* get the value */ - for (; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); Lexer->Pos++) + for (; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); LEXER_INC(Lexer)) Result = Result * Base + GET_BASE_DIGIT(*Lexer->Pos); if (Result <= MAX_CHAR_VALUE) @@ -170,14 +167,14 @@ enum LexToken LexGetNumber(struct LexState *Lexer, struct Value *Value) return ResultToken; Value->Typ = &FPType; - Lexer->Pos++; - for (FPDiv = 1.0/Base, FPResult = (double)Result; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); Lexer->Pos++, FPDiv /= (double)Base) + LEXER_INC(Lexer); + for (FPDiv = 1.0/Base, FPResult = (double)Result; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); LEXER_INC(Lexer), FPDiv /= (double)Base) FPResult += GET_BASE_DIGIT(*Lexer->Pos) * FPDiv; if (Lexer->Pos != Lexer->End && (*Lexer->Pos == 'e' || *Lexer->Pos == 'E')) { - Lexer->Pos++; - for (Result = 0; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); Lexer->Pos++) + LEXER_INC(Lexer); + for (Result = 0; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); LEXER_INC(Lexer)) Result = Result * (double)Base + GET_BASE_DIGIT(*Lexer->Pos); FPResult *= math_pow((double)Base, (double)Result); @@ -194,15 +191,15 @@ enum LexToken LexGetNumber(struct LexState *Lexer, struct Value *Value) /* get a reserved word or identifier - used while scanning */ enum LexToken LexGetWord(struct LexState *Lexer, struct Value *Value) { - const char *Pos = Lexer->Pos + 1; + const char *StartPos = Lexer->Pos; enum LexToken Token; - while (Lexer->Pos != Lexer->End && isCident(*Pos)) - Pos++; + do { + LEXER_INC(Lexer); + } while (Lexer->Pos != Lexer->End && isCident(*Lexer->Pos)); Value->Typ = NULL; - Value->Val->Identifier = TableStrRegister2(Lexer->Pos, Pos - Lexer->Pos); - Lexer->Pos = Pos; + Value->Val->Identifier = TableStrRegister2(StartPos, Lexer->Pos - StartPos); Token = LexCheckReservedWord(Value->Val->Identifier); if (Token != TokenNone) @@ -282,7 +279,7 @@ enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value) else if (*Lexer->Pos == '\\') Escape = TRUE; - Lexer->Pos++; + LEXER_INC(Lexer); } EndPos = Lexer->Pos; @@ -316,7 +313,7 @@ enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value) Value->Val->NativePointer = ArrayValue; #endif if (*Lexer->Pos == '"') - Lexer->Pos++; + LEXER_INC(Lexer); return TokenStringConstant; } @@ -329,28 +326,28 @@ enum LexToken LexGetCharacterConstant(struct LexState *Lexer, struct Value *Valu if (Lexer->Pos != Lexer->End && *Lexer->Pos != '\'') LexFail(Lexer, "expected \"'\""); - Lexer->Pos++; + LEXER_INC(Lexer); return TokenCharacterConstant; } /* skip a comment - used while scanning */ void LexSkipComment(struct LexState *Lexer, char NextChar) { - Lexer->Pos++; + LEXER_INC(Lexer); if (NextChar == '*') { /* conventional C comment */ while (Lexer->Pos != Lexer->End && (*(Lexer->Pos-1) != '*' || *Lexer->Pos != '/')) - Lexer->Pos++; + LEXER_INC(Lexer); if (Lexer->Pos != Lexer->End) - Lexer->Pos++; + LEXER_INC(Lexer); } else { /* C++ style comment */ while (Lexer->Pos != Lexer->End && *Lexer->Pos != '\n') - Lexer->Pos++; + LEXER_INC(Lexer); } } @@ -370,10 +367,13 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) { Lexer->Line++; Lexer->Pos++; +#ifdef FANCY_ERROR_REPORTING + Lexer->CharacterPos = 0; +#endif return TokenEndOfLine; } - Lexer->Pos++; + LEXER_INC(Lexer); } if (Lexer->Pos == Lexer->End || *Lexer->Pos == '\0') @@ -387,7 +387,7 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) return LexGetNumber(Lexer, *Value); NextChar = (Lexer->Pos+1 != Lexer->End) ? *(Lexer->Pos+1) : 0; - Lexer->Pos++; + LEXER_INC(Lexer); switch (ThisChar) { case '"': GotToken = LexGetStringConstant(Lexer, *Value); break; @@ -444,9 +444,17 @@ void *LexTokenise(struct LexState *Lexer, int *TokenLen) struct Value *GotValue; int MemUsed = 0; int ValueSize; +#ifdef FANCY_ERROR_REPORTING + int ReserveSpace = (Lexer->End - Lexer->Pos) * 4 + 1; +#else int ReserveSpace = (Lexer->End - Lexer->Pos) * 3 + 1; +#endif void *TokenSpace = HeapAllocStack(ReserveSpace); char *TokenPos = (char *)TokenSpace; +#ifdef FANCY_ERROR_REPORTING + int LastCharacterPos = 0; +#endif + if (TokenSpace == NULL) LexFail(Lexer, "out of memory"); @@ -461,6 +469,12 @@ void *LexTokenise(struct LexState *Lexer, int *TokenLen) TokenPos++; MemUsed++; +#ifdef FANCY_ERROR_REPORTING + *(unsigned char *)TokenPos = (unsigned char)LastCharacterPos; + TokenPos++; + MemUsed++; +#endif + ValueSize = LexTokenSize(Token); if (ValueSize > 0) { @@ -469,6 +483,10 @@ void *LexTokenise(struct LexState *Lexer, int *TokenLen) TokenPos += ValueSize; MemUsed += ValueSize; } + +#ifdef FANCY_ERROR_REPORTING + LastCharacterPos = Lexer->CharacterPos; +#endif } while (Token != TokenEOF); @@ -476,13 +494,14 @@ void *LexTokenise(struct LexState *Lexer, int *TokenLen) if (HeapMem == NULL) LexFail(Lexer, "out of memory"); + assert(ReserveSpace >= MemUsed); memcpy(HeapMem, TokenSpace, MemUsed); HeapPopStack(TokenSpace, ReserveSpace); #ifdef DEBUG_LEXER { int Count; for (Count = 0; Count < MemUsed; Count++) - printf("%02x ", *(unsigned char *)(HeapMem+Count)); + printf("%02x ", *((unsigned char *)HeapMem+Count)); printf("\n"); } #endif @@ -501,17 +520,25 @@ void *LexAnalyse(const char *FileName, const char *Source, int SourceLen, int *T Lexer.End = Source + SourceLen; Lexer.Line = 1; Lexer.FileName = FileName; +#ifdef FANCY_ERROR_REPORTING + Lexer.CharacterPos = 1; + Lexer.SourceText = Source; +#endif return LexTokenise(&Lexer, TokenLen); } /* prepare to parse a pre-tokenised buffer */ -void LexInitParser(struct ParseState *Parser, void *TokenSource, const char *FileName, int Line, int RunIt) +void LexInitParser(struct ParseState *Parser, const char *SourceText, void *TokenSource, const char *FileName, int RunIt) { Parser->Pos = TokenSource; - Parser->Line = Line; + Parser->Line = 1; Parser->FileName = FileName; Parser->Mode = RunIt ? RunModeRun : RunModeSkip; Parser->SearchLabel = 0; +#ifdef FANCY_ERROR_REPORTING + Parser->CharacterPos = 0; + Parser->SourceText = SourceText; +#endif } /* get the next token given a parser state */ @@ -532,7 +559,7 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I while ((Token = (enum LexToken)*(unsigned char *)Parser->Pos) == TokenEndOfLine) { Parser->Line++; - Parser->Pos++; + Parser->Pos += TOKEN_DATA_OFFSET; } } @@ -544,7 +571,7 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I int LineBytes; struct TokenLine *LineNode; - if (InteractiveHead == NULL || (unsigned char *)Parser->Pos == &InteractiveTail->Tokens[InteractiveTail->NumBytes-1]) + if (InteractiveHead == NULL || (unsigned char *)Parser->Pos == &InteractiveTail->Tokens[InteractiveTail->NumBytes-TOKEN_DATA_OFFSET]) { /* get interactive input */ if (LexUseStatementPrompt) @@ -568,6 +595,7 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I /* start a new list */ InteractiveHead = LineNode; Parser->Line = 1; + Parser->CharacterPos = 0; } else InteractiveTail->Next = LineNode; @@ -579,10 +607,10 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I else { /* go to the next token line */ - if (Parser->Pos != &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes-1]) + if (Parser->Pos != &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes-TOKEN_DATA_OFFSET]) { /* scan for the line */ - for (InteractiveCurrentLine = InteractiveHead; Parser->Pos != &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes-1]; InteractiveCurrentLine = InteractiveCurrentLine->Next) + for (InteractiveCurrentLine = InteractiveHead; Parser->Pos != &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes-TOKEN_DATA_OFFSET]; InteractiveCurrentLine = InteractiveCurrentLine->Next) {} } @@ -594,6 +622,10 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I } } while ((Parser->FileName == StrEmpty && Token == TokenEOF) || Token == TokenEndOfLine); +#ifdef FANCY_ERROR_REPORTING + Parser->CharacterPos = *((unsigned char *)Parser->Pos + 1); +#endif + ValueSize = LexTokenSize(Token); if (ValueSize > 0) { @@ -612,7 +644,7 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I default: break; } - memcpy((void *)LexValue.Val, (void *)((char *)Parser->Pos+1), ValueSize); + memcpy((void *)LexValue.Val, (void *)((char *)Parser->Pos + TOKEN_DATA_OFFSET), ValueSize); LexValue.ValOnHeap = FALSE; LexValue.ValOnStack = FALSE; LexValue.IsLValue = FALSE; @@ -621,16 +653,16 @@ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int I } if (IncPos) - Parser->Pos += ValueSize + 1; + Parser->Pos += ValueSize + TOKEN_DATA_OFFSET; } else { if (IncPos && Token != TokenEOF) - Parser->Pos++; + Parser->Pos += TOKEN_DATA_OFFSET; } #ifdef DEBUG_LEXER - printf("Got token=%02x inc=%d\n", Token, IncPos); + printf("Got token=%02x inc=%d pos=%d\n", Token, IncPos, Parser->CharacterPos); #endif return Token; } diff --git a/parse.c b/parse.c index 69fe88c..10ab757 100644 --- a/parse.c +++ b/parse.c @@ -188,6 +188,9 @@ void ParserCopyPos(struct ParseState *To, struct ParseState *From) { To->Pos = From->Pos; To->Line = From->Line; +#ifdef FANCY_ERROR_REPORTING + To->CharacterPos = From->CharacterPos; +#endif } /* parse a "for" statement */ @@ -572,7 +575,7 @@ void Parse(const char *FileName, const char *Source, int SourceLen, int RunIt) if (OldCleanupTokens == NULL) CleanupTokens = Tokens; - LexInitParser(&Parser, Tokens, FileName, 1, RunIt); + LexInitParser(&Parser, Source, Tokens, FileName, RunIt); do { Ok = ParseStatement(&Parser); @@ -593,7 +596,7 @@ void ParseInteractive() enum ParseResult Ok; PlatformPrintf(INTERACTIVE_PROMPT_START); - LexInitParser(&Parser, NULL, StrEmpty, 1, TRUE); + LexInitParser(&Parser, NULL, NULL, StrEmpty, TRUE); PlatformSetExitPoint(); LexInteractiveClear(&Parser); diff --git a/picoc.h b/picoc.h index 231ca72..a169f84 100644 --- a/picoc.h +++ b/picoc.h @@ -96,6 +96,10 @@ struct ParseState const char *FileName; enum RunMode Mode; /* whether to skip or run code */ int SearchLabel; /* what case label we're searching for */ +#ifdef FANCY_ERROR_REPORTING + int CharacterPos; + const char *SourceText; +#endif }; /* values */ @@ -229,8 +233,12 @@ struct LexState { const char *Pos; const char *End; - int Line; const char *FileName; + int Line; +#ifdef FANCY_ERROR_REPORTING + int CharacterPos; + const char *SourceText; +#endif }; /* library function definition */ @@ -261,6 +269,7 @@ struct OutputStream union OutputStreamInfo i; }; +/* possible results of parsing a statement */ enum ParseResult { ParseResultEOF, ParseResultError, ParseResultOk }; /* globals */ @@ -300,7 +309,7 @@ void TableStrFree(); void LexInit(); void LexCleanup(); void *LexAnalyse(const char *FileName, const char *Source, int SourceLen, int *TokenLen); -void LexInitParser(struct ParseState *Parser, void *TokenSource, const char *FileName, int Line, int RunIt); +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); void LexToEndOfLine(struct ParseState *Parser); void *LexCopyTokens(struct ParseState *StartParser, struct ParseState *EndParser); @@ -376,6 +385,7 @@ void PrintType(struct ValueType *Typ, struct OutputStream *Stream); /* platform.c */ 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(); void PlatformScanFile(const char *FileName); diff --git a/platform.c b/platform.c index d8da731..301a7ae 100644 --- a/platform.c +++ b/platform.c @@ -1,12 +1,58 @@ #include "picoc.h" +#ifdef FANCY_ERROR_REPORTING +void PrintSourceTextErrorLine(const char *FileName, const char *SourceText, int Line, int CharacterPos) +{ + int LineCount; + const char *LinePos; + const char *CPos; + int CCount; + + 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, &CStdOut); + PrintCh('\n', &CStdOut); + + /* display the error position */ + for (CPos = LinePos, CCount = 0; *CPos != '\n' && *CPos != '\0' && (CCount < CharacterPos || *CPos == ' '); CPos++, CCount++) + { + if (*CPos == '\t') + PrintCh('\t', &CStdOut); + else + PrintCh(' ', &CStdOut); + } + } + else + { + /* assume we're in interactive mode - try to make the arrow match up with the input text */ + for (CCount = 0; CCount < CharacterPos + strlen(INTERACTIVE_PROMPT_STATEMENT); CCount++) + PrintCh(' ', &CStdOut); + } + PlatformPrintf("^\n%s:%d: ", FileName, Line, CharacterPos); + +} +#endif + /* exit with a message */ void ProgramFail(struct ParseState *Parser, const char *Message, ...) { va_list Args; if (Parser != NULL) +#ifdef FANCY_ERROR_REPORTING + PrintSourceTextErrorLine(Parser->FileName, Parser->SourceText, Parser->Line, Parser->CharacterPos); +#else PlatformPrintf("%s:%d: ", Parser->FileName, Parser->Line); +#endif va_start(Args, Message); PlatformVPrintf(Message, Args); @@ -15,12 +61,40 @@ void ProgramFail(struct ParseState *Parser, const char *Message, ...) PlatformExit(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) +{ + if (Parser != NULL) +#ifdef FANCY_ERROR_REPORTING + PrintSourceTextErrorLine(Parser->FileName, Parser->SourceText, Parser->Line, Parser->CharacterPos); +#else + PlatformPrintf("%s:%d: ", Parser->FileName, Parser->Line); +#endif + + PlatformPrintf("can't %s ", (FuncName == NULL) ? "assign" : "set"); + + if (Type1 != NULL) + PlatformPrintf(Format, Type1, Type2); + else + PlatformPrintf(Format, Num1, Num2); + + if (FuncName != NULL) + PlatformPrintf(" in argument %d of call to %s()", ParamNo, FuncName); + + ProgramFail(NULL, ""); +} + /* exit lexing with a message */ void LexFail(struct LexState *Lexer, const char *Message, ...) { va_list Args; - PlatformPrintf("%s:%d: ", Lexer->FileName, Lexer->Line); +#ifdef FANCY_ERROR_REPORTING + PrintSourceTextErrorLine(Lexer->FileName, Lexer->SourceText, Lexer->Line, Lexer->CharacterPos); +#else + PlatformPrintf("%s:%d: ", Lexer->FileName, Lexer->Line); +#endif + va_start(Args, Message); PlatformVPrintf(Message, Args); va_end(Args); diff --git a/platform.h b/platform.h index 4194360..078b2e1 100644 --- a/platform.h +++ b/platform.h @@ -24,6 +24,8 @@ #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 FANCY_ERROR_REPORTING /* optional feature - gives more detailed error messages but uses more memory */ + #define INTERACTIVE_PROMPT_START "starting picoc\n" #define INTERACTIVE_PROMPT_STATEMENT "picoc> " #define INTERACTIVE_PROMPT_LINE " > "