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:
Kugel Fuhr
2025-07-04 17:11:34 +02:00
parent 500b86f1e2
commit bcd29de443
46 changed files with 779 additions and 342 deletions

View File

@@ -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;
}