Much improved error messages for ca65. For most errors it will now say what
was expected and what was found instead. Also improved error recovery in a few places.
This commit is contained in:
304
src/ca65/token.c
304
src/ca65/token.c
@@ -33,30 +33,261 @@
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* ca65 */
|
||||
#include "token.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
int TokHasSVal (token_t Tok)
|
||||
/* Return true if the given token has an attached SVal */
|
||||
{
|
||||
return (Tok == TOK_IDENT || Tok == TOK_LOCAL_IDENT || Tok == TOK_STRCON);
|
||||
}
|
||||
/* Use a struct so we can extend it if required */
|
||||
typedef struct TokDescEntry TokDescEntry;
|
||||
struct TokDescEntry {
|
||||
const char* Desc;
|
||||
};
|
||||
|
||||
static const TokDescEntry TokDesc[] = {
|
||||
{ "none", },
|
||||
{ "end-of-file", },
|
||||
{ "end-of-line", },
|
||||
{ "{s}", },
|
||||
{ "{s}", },
|
||||
|
||||
{ "{i}", },
|
||||
{ "'{c}'", },
|
||||
{ "\"{s}\"", },
|
||||
|
||||
{ "A", },
|
||||
{ "Q", },
|
||||
{ "S", },
|
||||
{ "X", },
|
||||
{ "Y", },
|
||||
{ "Z", },
|
||||
{ "R{i}", },
|
||||
|
||||
{ ":=", },
|
||||
{ "unnamed label", },
|
||||
|
||||
{ "=", },
|
||||
{ "<>", },
|
||||
{ "<", },
|
||||
{ ">", },
|
||||
{ "<=", },
|
||||
{ ">=", },
|
||||
|
||||
{ ".AND", },
|
||||
{ ".OR", },
|
||||
{ ".XOR", },
|
||||
{ ".NOT", },
|
||||
|
||||
{ "+", },
|
||||
{ "-", },
|
||||
{ "*", },
|
||||
{ "/", },
|
||||
{ "!", },
|
||||
{ "|", },
|
||||
{ "^", },
|
||||
{ "&", },
|
||||
{ "<<", },
|
||||
{ ">>", },
|
||||
{ "~", },
|
||||
|
||||
{ "$", },
|
||||
{ "::", },
|
||||
{ ".", },
|
||||
{ ",", },
|
||||
{ "#", },
|
||||
{ ":", },
|
||||
{ "(", },
|
||||
{ ")", },
|
||||
{ "[", },
|
||||
{ "]", },
|
||||
{ "{", },
|
||||
{ "}", },
|
||||
{ "@", },
|
||||
|
||||
{ "z:", },
|
||||
{ "a:", },
|
||||
{ "f:", },
|
||||
|
||||
{ "macro parameter", },
|
||||
{ "repeat counter", },
|
||||
|
||||
{ ".A16" },
|
||||
{ ".A8" },
|
||||
{ ".ADDR" },
|
||||
{ ".ADDRSIZE" },
|
||||
{ ".ALIGN" },
|
||||
{ ".ASCIIZ" },
|
||||
{ ".ASIZE" },
|
||||
{ ".ASSERT" },
|
||||
{ ".AUTOIMPORT" },
|
||||
{ ".BANK" },
|
||||
{ ".BANKBYTE" },
|
||||
{ ".BANKBYTES" },
|
||||
{ ".BLANK" },
|
||||
{ ".BSS" },
|
||||
{ ".BYTE" },
|
||||
{ ".CAP" },
|
||||
{ ".CASE" },
|
||||
{ ".CHARMAP" },
|
||||
{ ".CODE" },
|
||||
{ ".CONCAT" },
|
||||
{ ".CONDES" },
|
||||
{ ".CONST" },
|
||||
{ ".CONSTRUCTOR" },
|
||||
{ ".CPU" },
|
||||
{ ".DATA" },
|
||||
{ ".DBG" },
|
||||
{ ".DBYT" },
|
||||
{ ".DEBUGINFO" },
|
||||
{ ".DEFINE" },
|
||||
{ ".DEFINED" },
|
||||
{ ".DEFINEDMACRO" },
|
||||
{ ".DELMAC" },
|
||||
{ ".DESTRUCTOR" },
|
||||
{ ".DWORD" },
|
||||
{ ".ELSE" },
|
||||
{ ".ELSEIF" },
|
||||
{ ".END" },
|
||||
{ ".ENDENUM" },
|
||||
{ ".ENDIF" },
|
||||
{ ".ENDMACRO" },
|
||||
{ ".ENDPROC" },
|
||||
{ ".ENDREP" },
|
||||
{ ".ENDSCOPE" },
|
||||
{ ".ENDSTRUCT" },
|
||||
{ ".ENDUNION" },
|
||||
{ ".ENUM" },
|
||||
{ ".ERROR" },
|
||||
{ ".EXITMACRO" },
|
||||
{ ".EXPORT" },
|
||||
{ ".EXPORTZP" },
|
||||
{ ".FARADDR" },
|
||||
{ ".FATAL" },
|
||||
{ ".FEATURE" },
|
||||
{ ".FILEOPT" },
|
||||
{ ".FORCEIMPORT" },
|
||||
{ ".FORCEWORD" },
|
||||
{ ".GLOBAL" },
|
||||
{ ".GLOBALZP" },
|
||||
{ ".HIBYTE" },
|
||||
{ ".HIBYTES" },
|
||||
{ ".HIWORD" },
|
||||
{ ".I16" },
|
||||
{ ".I8" },
|
||||
{ ".MAKEIDENT" },
|
||||
{ ".IF" },
|
||||
{ ".IFBLANK" },
|
||||
{ ".IFCONST" },
|
||||
{ ".IFDEF" },
|
||||
{ ".IFNBLANK" },
|
||||
{ ".IFNCONST" },
|
||||
{ ".IFNDEF" },
|
||||
{ ".IFNREF" },
|
||||
{ ".IFP02" },
|
||||
{ ".IFP02X" },
|
||||
{ ".IFP4510" },
|
||||
{ ".IFP45GS02" },
|
||||
{ ".IFP6280" },
|
||||
{ ".IFP816" },
|
||||
{ ".IFPC02" },
|
||||
{ ".IFPCE02" },
|
||||
{ ".IFPDTV" },
|
||||
{ ".IFPM740" },
|
||||
{ ".IFPSC02" },
|
||||
{ ".IFPSWEET16" },
|
||||
{ ".IFPWC02" },
|
||||
{ ".IFREF" },
|
||||
{ ".IMPORT" },
|
||||
{ ".IMPORTZP" },
|
||||
{ ".INCBIN" },
|
||||
{ ".INCLUDE" },
|
||||
{ ".INTERRUPTOR" },
|
||||
{ ".ISIZE" },
|
||||
{ ".ISMNEMONIC" },
|
||||
{ ".LEFT" },
|
||||
{ ".LINECONT" },
|
||||
{ ".LIST" },
|
||||
{ ".LISTBYTES" },
|
||||
{ ".LITERAL" },
|
||||
{ ".LOBYTE" },
|
||||
{ ".LOBYTES" },
|
||||
{ ".LOCAL" },
|
||||
{ ".LOCALCHAR" },
|
||||
{ ".LOWORD" },
|
||||
{ ".MACPACK" },
|
||||
{ ".MACRO" },
|
||||
{ ".MATCH" },
|
||||
{ ".MAX" },
|
||||
{ ".MID" },
|
||||
{ ".MIN" },
|
||||
{ ".NULL" },
|
||||
{ ".ORG" },
|
||||
{ ".OUT" },
|
||||
{ ".P02" },
|
||||
{ ".P02X" },
|
||||
{ ".P4510" },
|
||||
{ ".P45GS02" },
|
||||
{ ".P6280" },
|
||||
{ ".P816" },
|
||||
{ ".PAGELENGTH" },
|
||||
{ ".PARAMCOUNT" },
|
||||
{ ".PC02" },
|
||||
{ ".PCE02" },
|
||||
{ ".PDTV" },
|
||||
{ ".PM740" },
|
||||
{ ".POPCHARMAP" },
|
||||
{ ".POPCPU" },
|
||||
{ ".POPSEG" },
|
||||
{ ".PROC" },
|
||||
{ ".PSC02" },
|
||||
{ ".PSWEET16" },
|
||||
{ ".PUSHCHARMAP" },
|
||||
{ ".PUSHCPU" },
|
||||
{ ".PUSHSEG" },
|
||||
{ ".PWC02" },
|
||||
{ ".REFERENCED" },
|
||||
{ ".REFERTO" },
|
||||
{ ".RELOC" },
|
||||
{ ".REPEAT" },
|
||||
{ ".RES" },
|
||||
{ ".RIGHT" },
|
||||
{ ".RODATA" },
|
||||
{ ".SCOPE" },
|
||||
{ ".SEGMENT" },
|
||||
{ ".SET" },
|
||||
{ ".SETCPU" },
|
||||
{ ".SIZEOF" },
|
||||
{ ".SMART" },
|
||||
{ ".SPRINTF" },
|
||||
{ ".STRAT" },
|
||||
{ ".STRING" },
|
||||
{ ".STRLEN" },
|
||||
{ ".STRUCT" },
|
||||
{ ".TAG" },
|
||||
{ ".TCOUNT" },
|
||||
{ ".TIME" },
|
||||
{ ".UNDEF" },
|
||||
{ ".UNION" },
|
||||
{ ".VERSION" },
|
||||
{ ".WARNING" },
|
||||
{ ".WORD" },
|
||||
{ ".XMATCH" },
|
||||
{ ".ZEROPAGE" },
|
||||
};
|
||||
|
||||
|
||||
|
||||
int TokHasIVal (token_t Tok)
|
||||
/* Return true if the given token has an attached IVal */
|
||||
{
|
||||
return (Tok == TOK_INTCON || Tok == TOK_CHARCON || Tok == TOK_REG);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
@@ -72,3 +303,54 @@ void CopyToken (Token* Dst, const Token* Src)
|
||||
SB_Copy (&Dst->SVal, &Src->SVal);
|
||||
Dst->Pos = Src->Pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
StrBuf* TokenDesc (const Token* T, StrBuf* S)
|
||||
/* Place a textual description of the given token into S. */
|
||||
{
|
||||
PRECONDITION (sizeof (TokDesc) / sizeof (TokDesc[0]) == TOK_COUNT);
|
||||
|
||||
/* Clear the target buffer */
|
||||
SB_Clear (S);
|
||||
|
||||
/* Get the description for the token */
|
||||
const char* Desc = TokDesc[T->Tok].Desc;
|
||||
|
||||
/* Repeatedly replace {c}, {i} and {s} */
|
||||
size_t Start = 0;
|
||||
while (1) {
|
||||
const char* P = strchr (Desc + Start, '{');
|
||||
if (P) {
|
||||
/* Check if this is really {c}, {i} or {s} */
|
||||
if ((P[1] != 'c' &&
|
||||
P[1] != 'i' &&
|
||||
P[1] != 's') ||
|
||||
P[2] != '}') {
|
||||
++Start;
|
||||
continue;
|
||||
}
|
||||
/* Append the text before the replacement token */
|
||||
SB_AppendBuf (S, Desc + Start, P - (Desc + Start));
|
||||
Start += P - (Desc + Start) + 3;
|
||||
/* Append the replacement text */
|
||||
if (P[1] == 'c') {
|
||||
SB_AppendChar (S, (char)T->IVal);
|
||||
} else if (P[1] == 'i') {
|
||||
char Buf[64];
|
||||
snprintf (Buf, sizeof (Buf), "%ld", T->IVal);
|
||||
SB_AppendStr (S, Buf);
|
||||
} else {
|
||||
SB_Append (S, &T->SVal);
|
||||
}
|
||||
} else {
|
||||
/* No more replacements found, append remainder */
|
||||
SB_AppendStr (S, Desc + Start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Zero-terminate the buffer and return it */
|
||||
SB_Terminate (S);
|
||||
return S;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user