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

@@ -194,7 +194,7 @@ static void FreeIf (void)
{
int Done;
do {
IfDesc* ID = GetCurrentIf();
IfDesc* ID = GetCurrentIf ();
if (ID == 0) {
Error (" Unexpected .ENDIF");
Done = 1;
@@ -318,7 +318,7 @@ void DoConditionals (void)
D = AllocIf (".IFCONST", 1);
NextTok ();
if (IfCond) {
ExprNode* Expr = Expression();
ExprNode* Expr = Expression ();
SetIfCond (D, IsConstExpr (Expr, 0));
FreeExpr (Expr);
ExpectSep ();
@@ -354,7 +354,7 @@ void DoConditionals (void)
D = AllocIf (".IFNCONST", 1);
NextTok ();
if (IfCond) {
ExprNode* Expr = Expression();
ExprNode* Expr = Expression ();
SetIfCond (D, !IsConstExpr (Expr, 0));
FreeExpr (Expr);
ExpectSep ();
@@ -388,7 +388,7 @@ void DoConditionals (void)
D = AllocIf (".IFP02", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_6502);
SetIfCond (D, GetCPU () == CPU_6502);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -398,7 +398,7 @@ void DoConditionals (void)
D = AllocIf (".IFP02X", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_6502X);
SetIfCond (D, GetCPU () == CPU_6502X);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -408,7 +408,7 @@ void DoConditionals (void)
D = AllocIf (".IFP4510", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_4510);
SetIfCond (D, GetCPU () == CPU_4510);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -418,7 +418,7 @@ void DoConditionals (void)
D = AllocIf (".IFP45GS02", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_45GS02);
SetIfCond (D, GetCPU () == CPU_45GS02);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -428,7 +428,7 @@ void DoConditionals (void)
D = AllocIf (".IFP6280", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_HUC6280);
SetIfCond (D, GetCPU () == CPU_HUC6280);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -438,7 +438,7 @@ void DoConditionals (void)
D = AllocIf (".IFP816", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_65816);
SetIfCond (D, GetCPU () == CPU_65816);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -448,7 +448,7 @@ void DoConditionals (void)
D = AllocIf (".IFPC02", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_65C02);
SetIfCond (D, GetCPU () == CPU_65C02);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -458,7 +458,7 @@ void DoConditionals (void)
D = AllocIf (".IFPCE02", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_65CE02);
SetIfCond (D, GetCPU () == CPU_65CE02);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -468,7 +468,7 @@ void DoConditionals (void)
D = AllocIf (".IFPDTV", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_6502DTV);
SetIfCond (D, GetCPU () == CPU_6502DTV);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -478,7 +478,7 @@ void DoConditionals (void)
D = AllocIf (".IFPM740", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_M740);
SetIfCond (D, GetCPU () == CPU_M740);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -488,7 +488,7 @@ void DoConditionals (void)
D = AllocIf (".IFPSC02", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_65SC02);
SetIfCond (D, GetCPU () == CPU_65SC02);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -498,7 +498,7 @@ void DoConditionals (void)
D = AllocIf (".IFPSWEET16", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_SWEET16);
SetIfCond (D, GetCPU () == CPU_SWEET16);
}
ExpectSep ();
CalcOverallIfCond ();
@@ -508,7 +508,7 @@ void DoConditionals (void)
D = AllocIf (".IFPWC02", 1);
NextTok ();
if (IfCond) {
SetIfCond (D, GetCPU() == CPU_W65C02);
SetIfCond (D, GetCPU () == CPU_W65C02);
}
ExpectSep ();
CalcOverallIfCond ();

View File

@@ -238,8 +238,7 @@ void DbgInfoFunc (void)
ConsumeComma ();
/* Type */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
if (!ExpectSkip (TOK_STRCON, "Expected a string constant")) {
return;
}
Type = ValidateType (&CurTok.SVal);
@@ -267,8 +266,7 @@ void DbgInfoFunc (void)
ConsumeComma ();
/* Assembler name follows */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
if (!ExpectSkip (TOK_STRCON, "Expected a string constant")) {
return;
}
AsmName = GetStrBufId (&CurTok.SVal);
@@ -321,8 +319,7 @@ void DbgInfoLine (void)
ConsumeComma ();
/* The name of the file follows */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
if (!ExpectSkip (TOK_STRCON, "Expected a string constant")) {
return;
}
@@ -371,8 +368,7 @@ void DbgInfoSym (void)
ConsumeComma ();
/* Name */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
if (!ExpectSkip (TOK_STRCON, "Expected a string constant")) {
return;
}
Name = GetStrBufId (&CurTok.SVal);
@@ -382,8 +378,7 @@ void DbgInfoSym (void)
ConsumeComma ();
/* Type */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
if (!ExpectSkip (TOK_STRCON, "Expected a string constant")) {
return;
}
Type = ValidateType (&CurTok.SVal);
@@ -418,8 +413,7 @@ void DbgInfoSym (void)
Offs = ConstExpression ();
} else {
/* Register, extern or static: Assembler name follows */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
if (!ExpectSkip (TOK_STRCON, "Expected a string constant")) {
return;
}
AsmName = GetStrBufId (&CurTok.SVal);

View File

@@ -62,11 +62,11 @@ void GetEA (EffAddr* A)
if (BracketAsIndirect) {
IndirectEnter = TOK_LBRACK;
IndirectLeave = TOK_RBRACK;
IndirectExpect = "']' expected";
IndirectExpect = "Expected ']'";
} else {
IndirectEnter = TOK_LPAREN;
IndirectLeave = TOK_RPAREN;
IndirectExpect = "')' expected";
IndirectExpect = "Expected ')'";
}
/* Clear the output struct */
@@ -136,16 +136,22 @@ void GetEA (EffAddr* A)
/* (adr,x) */
NextTok ();
A->AddrModeSet = AM65_ABS_X_IND | AM65_DIR_X_IND;
Consume (IndirectLeave, IndirectExpect);
if (!Consume (IndirectLeave, IndirectExpect)) {
SkipUntilSep ();
}
} else if (CurTok.Tok == TOK_S) {
/* (rel,s),y */
NextTok ();
A->AddrModeSet = AM65_STACK_REL_IND_Y;
Consume (IndirectLeave, IndirectExpect);
ConsumeComma ();
Consume (TOK_Y, "'Y' expected");
if (!Consume (IndirectLeave, IndirectExpect) ||
!ConsumeComma () ||
!Consume (TOK_Y, "Expected 'Y'")) {
/* In case of errors skip anything else on the line */
SkipUntilSep ();
}
} else {
Error ("Syntax error");
ErrorExpect ("Expected 'X' or 'S'");
SkipUntilSep ();
}
} else {
@@ -162,7 +168,9 @@ void GetEA (EffAddr* A)
A->AddrModeSet = AM65_DIR_IND;
break;
default:
Consume (TOK_Y, "'Y' expected");
if (!Consume (TOK_Y, "Expected 'Y'")) {
SkipUntilSep ();
}
A->AddrModeSet = AM65_DIR_IND_Y;
break;
}
@@ -190,16 +198,22 @@ void GetEA (EffAddr* A)
/* [dir] or [dir],y */
NextTok ();
A->Expr = Expression ();
Consume (TOK_RBRACK, "']' expected");
if (!Consume (TOK_RBRACK, "Expected ']'")) {
SkipUntilSep ();
}
if (CurTok.Tok == TOK_COMMA) {
/* [dir],y */
NextTok ();
if (GetCPU () == CPU_45GS02) {
Consume (TOK_Z, "'Z' expected");
if (!Consume (TOK_Z, "Expected 'Z'")) {
SkipUntilSep ();
}
A->AddrModeSet = AM65_32BIT_BASE_IND_Z;
}
else {
Consume (TOK_Y, "'Y' expected");
if (!Consume (TOK_Y, "Expected 'Y'")) {
SkipUntilSep ();
}
A->AddrModeSet = AM65_DIR_IND_LONG_Y;
}
} else {

View File

@@ -96,7 +96,7 @@ void GetSweet16EA (EffAddr* A)
/* Register number */
A->Reg = (unsigned) Reg;
} else {
ErrorSkip ("Register or register number expected");
ErrorExpect ("Expected register or register number");
A->Reg = 0;
}

View File

@@ -87,12 +87,13 @@ void DoEnum (void)
continue;
}
/* Allow conditionals within an enum */
if (CheckConditionals ()) {
continue;
}
/* The format is "identifier [ = value ]" */
if (CurTok.Tok != TOK_IDENT) {
/* Maybe it's a conditional? */
if (!CheckConditionals ()) {
ErrorSkip ("Identifier expected");
}
if (!ExpectSkip (TOK_IDENT, "Expected an identifier")) {
continue;
}

View File

@@ -421,8 +421,7 @@ static ExprNode* FuncCapability (void)
capability_t Cap;
/* We must have an identifier */
if (CurTok.Tok != TOK_IDENT) {
Error ("Arguments to .CAPABILITY must be identifiers");
if (!Expect (TOK_IDENT, "Expected a capability name")) {
/* Skip tokens until closing paren or end of line */
while (CurTok.Tok != TOK_RPAREN && !TokIsSep (CurTok.Tok)) {
NextTok ();
@@ -942,8 +941,7 @@ static ExprNode* FuncStrAt (void)
unsigned char C = 0;
/* String constant expected */
if (CurTok.Tok != TOK_STRCON) {
Error ("String constant expected");
if (!Expect (TOK_STRCON, "Expected a string constant")) {
NextTok ();
goto ExitPoint;
}
@@ -985,9 +983,8 @@ static ExprNode* FuncStrLen (void)
int Len;
/* String constant expected */
if (CurTok.Tok != TOK_STRCON) {
if (!Expect (TOK_STRCON, "Expected a string constant")) {
Error ("String constant expected");
/* Smart error recovery */
if (CurTok.Tok != TOK_RPAREN) {
NextTok ();
@@ -1062,9 +1059,7 @@ static ExprNode* Function (ExprNode* (*F) (void))
NextTok ();
/* Expression must be enclosed in braces */
if (CurTok.Tok != TOK_LPAREN) {
Error ("'(' expected");
SkipUntilSep ();
if (!ExpectSkip (TOK_LPAREN, "Expected '('")) {
return GenLiteral0 ();
}
NextTok ();
@@ -1296,7 +1291,7 @@ static ExprNode* Factor (void)
NextTok ();
} else {
N = GenLiteral0 (); /* Dummy */
Error ("Syntax error");
ErrorExpect ("Expected an expression");
}
break;
}
@@ -1957,9 +1952,8 @@ ExprNode* GenNearAddrExpr (ExprNode* Expr)
if (IsEasyConst (Expr, &Val)) {
FreeExpr (Expr);
Expr = GenLiteralExpr (Val & 0xFFFF);
if (Val > 0xFFFF)
{
Error("Range error: constant too large for assumed near address.");
if (Val > 0xFFFF) {
Error ("Range error: constant too large for assumed near address.");
}
} else {
ExprNode* Operand = Expr;

View File

@@ -2091,7 +2091,7 @@ static void PutBitBranch_m740 (const InsDesc* Ins)
EffAddr A;
/* Evaluate the addressing mode used */
GetEA(&A);
GetEA (&A);
/* From the possible addressing modes, remove the ones that are invalid
** for this instruction or CPU.
@@ -2375,7 +2375,7 @@ static void PutJSR_m740 (const InsDesc* Ins)
/* direct page */
A.Opcode = 0x22;
Emit0 (A.Opcode);
EmitByte(GenByteExpr(A.Expr));
EmitByte (GenByteExpr (A.Expr));
return;
}
}

View File

@@ -406,11 +406,11 @@ void MacDef (unsigned Style)
Pos = CurTok.Pos;
/* We expect a macro name here */
if (CurTok.Tok != TOK_IDENT) {
Error ("Identifier expected");
if (!Expect (TOK_IDENT, "Expected an identifier")) {
MacSkipDef (Style);
return;
} else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
}
if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
/* The identifier is a name of a 6502 instruction, which is not
** allowed if not explicitly enabled.
*/
@@ -439,7 +439,7 @@ void MacDef (unsigned Style)
** otherwise, we may have parameters without parentheses.
*/
if (Style == MAC_STYLE_CLASSIC) {
HaveParams = 1;
HaveParams = (CurTok.Tok != TOK_SEP);
} else {
if (CurTok.Tok == TOK_LPAREN) {
HaveParams = 1;
@@ -451,7 +451,7 @@ void MacDef (unsigned Style)
/* Parse the parameter list */
if (HaveParams) {
while (CurTok.Tok == TOK_IDENT) {
while (Expect (TOK_IDENT, "Expected a parameter name")) {
/* Create a struct holding the identifier */
IdDesc* I = NewIdDesc (&CurTok.SVal);
@@ -533,7 +533,7 @@ void MacDef (unsigned Style)
/* Need an identifer */
if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) {
Error ("Identifier expected");
ErrorExpect ("Expected an identifier");
SkipUntilSep ();
break;
}
@@ -591,7 +591,7 @@ void MacDef (unsigned Style)
/* Save if last token was a separator to know if .endmacro is at
** the start of a line
*/
LastTokWasSep = TokIsSep(CurTok.Tok);
LastTokWasSep = TokIsSep (CurTok.Tok);
/* Read the next token */
NextTok ();
@@ -938,10 +938,8 @@ static void StartExpDefine (MacExp* E)
/* Check for a comma */
if (Count > 0) {
if (CurTok.Tok == TOK_COMMA) {
if (Expect (TOK_COMMA, "Expected ','")) {
NextTok ();
} else {
Error ("',' expected");
}
}
}

View File

@@ -145,7 +145,7 @@ static void SetOptions (void)
OptTranslator (&Buf);
/* Set date and time */
OptDateTime ((unsigned long) time(0));
OptDateTime ((unsigned long) time (0));
/* Release memory for the string */
SB_Done (&Buf);
@@ -708,7 +708,7 @@ static void OptVersion (const char* Opt attribute ((unused)),
/* Print the assembler version */
{
fprintf (stderr, "%s V%s\n", ProgName, GetVersionAsString ());
exit(EXIT_SUCCESS);
exit (EXIT_SUCCESS);
}
@@ -727,7 +727,7 @@ static void DoPCAssign (void)
{
long PC = ConstExpression ();
if (PC < 0 || PC > 0xFFFFFF) {
Error ("Range error");
Error ("Program counter value is out of valid range");
} else {
EnterAbsoluteMode (PC);
}
@@ -820,11 +820,10 @@ static void OneLine (void)
NextTok ();
/* Define the symbol with the expression following the '=' */
SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags);
SymDef (Sym, Expression (), ADDR_SIZE_DEFAULT, Flags);
/* Don't allow anything after a symbol definition */
ConsumeSep ();
return;
goto Done;
} else if (CurTok.Tok == TOK_SET) {
@@ -842,8 +841,7 @@ static void OneLine (void)
SymDef (Sym, Expr, ADDR_SIZE_DEFAULT, SF_VAR);
/* Don't allow anything after a symbol definition */
ConsumeSep ();
return;
goto Done;
} else {
@@ -859,7 +857,8 @@ static void OneLine (void)
*/
if (CurTok.Tok != TOK_COLON) {
if (HadWS || !NoColonLabels) {
ErrorSkip ("Expected ':' after identifier to form a label");
ErrorExpect ("Expected ':' after identifier to form a label");
SkipUntilSep ();
goto Done;
}
} else {
@@ -903,17 +902,23 @@ static void OneLine (void)
HandleInstruction (Instr);
} else if (PCAssignment && (CurTok.Tok == TOK_STAR || CurTok.Tok == TOK_PC)) {
NextTok ();
if (CurTok.Tok != TOK_EQ) {
ErrorSkip ("'=' expected");
if (!ExpectSkip (TOK_EQ, "Expected '='")) {
goto Done;
} else {
/* Skip the equal sign */
NextTok ();
/* Enter absolute mode */
DoPCAssign ();
}
/* Skip the equal sign */
NextTok ();
/* Enter absolute mode */
DoPCAssign ();
} else if ((CurTok.Tok >= TOK_FIRSTOP && CurTok.Tok <= TOK_LASTOP) ||
(CurTok.Tok >= TOK_FIRSTREG && CurTok.Tok <= TOK_LASTREG) ||
CurTok.Tok == TOK_INTCON || CurTok.Tok == TOK_CHARCON ||
CurTok.Tok == TOK_STRCON) {
ErrorExpect ("Expected a mnemonic");
SkipUntilSep ();
goto Done;
}
/* If we have defined a label, remember its size. Sym is also set by
** a symbol assignment, but in this case Done is false, so we don't
** come here.
@@ -1233,7 +1238,7 @@ int main (int argc, char* argv [])
}
if (WarningCount > 0 && WarningsAsErrors) {
Error("Warnings as errors");
Error ("Warnings as errors");
}
/* If we didn't have an errors, finish off the line infos */

View File

@@ -725,52 +725,118 @@ void NextTok (void)
void Consume (token_t Expected, const char* ErrMsg)
/* Consume Expected, print an error if we don't find it */
void ErrorExpect (const char* Msg)
/* Output an error message about some expected token using Msg and the
* description of the following token. This means that Msg should contain
* something like "xyz expected". The actual error message would the be
* "xyz expected but found zyx".
*/
{
StrBuf S = AUTO_STRBUF_INITIALIZER;
TokenDesc (&CurTok, &S);
Error ("%s but found '%s'", Msg, SB_GetConstBuf (&S));
SB_Done (&S);
}
int Expect (token_t Expected, const char* Msg)
/* Check if the next token is the expected one. If not, print Msg plus some
* information about the token that was actually found. This means that Msg
* should contain something like "xyz expected". The actual error message would
* the be "xyz expected but found zyx".
* Returns true if the token was found, otherwise false.
*/
{
if (CurTok.Tok == Expected) {
return 1;
}
ErrorExpect (Msg);
return 0;
}
int ExpectSkip (token_t Expected, const char* Msg)
/* Check if the next token is the expected one. If not, print Msg plus some
* information about the token that was actually found and skip the remainder
* of the line. This means that Msg should contain something like "xyz
* expected". The actual error message would the be "xyz expected but found
* zyx".
* Returns true if the token was found, otherwise false.
*/
{
if (CurTok.Tok == Expected) {
return 1;
}
ErrorExpect (Msg);
SkipUntilSep ();
return 0;
}
int Consume (token_t Expected, const char* ErrMsg)
/* Consume Token, print an error if we don't find it. Return true if the token
** was found and false otherwise.
*/
{
if (Expect (Expected, ErrMsg)) {
NextTok ();
return 1;
} else {
Error ("%s", ErrMsg);
return 0;
}
}
void ConsumeSep (void)
/* Consume a separator token */
int ConsumeSep (void)
/* Consume a separator token. Return true if the token was found and false
* otherwise.
*/
{
/* We expect a separator token */
ExpectSep ();
int Found = ExpectSep ();
/* If we are at end of line, skip it */
if (CurTok.Tok == TOK_SEP) {
NextTok ();
}
return Found;
}
void ConsumeLParen (void)
/* Consume a left paren */
int ConsumeLParen (void)
/* Consume a left paren. Return true if the token was found and false
** otherwise.
*/
{
Consume (TOK_LPAREN, "'(' expected");
return Consume (TOK_LPAREN, "Expected '('");
}
void ConsumeRParen (void)
/* Consume a right paren */
int ConsumeRParen (void)
/* Consume a right paren. Return true if the token was found and false
** otherwise.
*/
{
Consume (TOK_RPAREN, "')' expected");
return Consume (TOK_RPAREN, "Expected ')'");
}
void ConsumeComma (void)
/* Consume a comma */
int ConsumeComma (void)
/* Consume a comma. Return true if the token was found and false
** otherwise.
*/
{
Consume (TOK_COMMA, "',' expected");
return Consume (TOK_COMMA, "Expected ','");
}
@@ -785,13 +851,21 @@ void SkipUntilSep (void)
void ExpectSep (void)
/* Check if we've reached a line separator, and output an error if not. Do
** not skip the line separator.
int ExpectSep (void)
/* Check if we've reached a line separator. If so, return true. If not, output
** an error and skip all tokens until the line separator is reached. Then
** return false.
*/
{
if (!TokIsSep (CurTok.Tok)) {
ErrorSkip ("Unexpected trailing garbage characters");
/* Try to be helpful by giving information about the token that was
* unexpected.
*/
ErrorExpect ("Expected 'end-of-line'");
SkipUntilSep ();
return 0;
} else {
return 1;
}
}

View File

@@ -51,27 +51,62 @@
void NextTok (void);
/* Get next token and handle token level functions */
void Consume (token_t Expected, const char* ErrMsg);
/* Consume Token, print an error if we don't find it */
void ErrorExpect (const char* Msg);
/* Output an error message about some expected token using Msg and the
* description of the following token. This means that Msg should contain
* something like "xyz expected". The actual error message would the be
* "xyz expected but found zyx".
*/
void ConsumeSep (void);
/* Consume a separator token */
int Expect (token_t Expected, const char* Msg);
/* Check if the next token is the expected one. If not, print Msg plus some
* information about the token that was actually found. This means that Msg
* should contain something like "xyz expected". The actual error message would
* the be "xyz expected but found zyx".
* Returns true if the token was found, otherwise false.
*/
void ConsumeLParen (void);
/* Consume a left paren */
int ExpectSkip (token_t Expected, const char* Msg);
/* Check if the next token is the expected one. If not, print Msg plus some
* information about the token that was actually found and skip the remainder
* of the line. This means that Msg should contain something like "xyz
* expected". The actual error message would the be "xyz expected but found
* zyx".
* Returns true if the token was found, otherwise false.
*/
void ConsumeRParen (void);
/* Consume a right paren */
int Consume (token_t Expected, const char* ErrMsg);
/* Consume Token, print an error if we don't find it. Return true if the token
** was found and false otherwise.
*/
void ConsumeComma (void);
/* Consume a comma */
int ConsumeSep (void);
/* Consume a separator token. Return true if the token was found and false
* otherwise.
*/
int ConsumeLParen (void);
/* Consume a left paren. Return true if the token was found and false
** otherwise.
*/
int ConsumeRParen (void);
/* Consume a right paren. Return true if the token was found and false
** otherwise.
*/
int ConsumeComma (void);
/* Consume a comma. Return true if the token was found and false
** otherwise.
*/
void SkipUntilSep (void);
/* Skip tokens until we reach a line separator or end of file */
void ExpectSep (void);
/* Check if we've reached a line separator, and output an error if not. Do
** not skip the line separator.
int ExpectSep (void);
/* Check if we've reached a line separator. If so, return true. If not, output
** an error and skip all tokens until the line separator is reached. Then
** return false.
*/
void EnterRawTokenMode (void);

View File

@@ -167,13 +167,17 @@ static void SetBoolOption (unsigned char* Flag)
switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
case 0: *Flag = 0; NextTok (); break;
case 1: *Flag = 1; NextTok (); break;
default: ErrorSkip ("'on' or 'off' expected"); break;
default:
ErrorExpect ("Expected ON or OFF");
SkipUntilSep ();
break;
}
} else if (TokIsSep (CurTok.Tok)) {
/* Without anything assume switch on */
*Flag = 1;
} else {
ErrorSkip ("'on' or 'off' expected");
ErrorExpect ("Expected ON or OFF");
SkipUntilSep ();
}
}
@@ -216,8 +220,7 @@ static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned),
while (1) {
/* We need an identifier here */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
if (!ExpectSkip (TOK_IDENT, "Expected an identifier")) {
return;
}
@@ -283,7 +286,7 @@ static void ConDes (const StrBuf* Name, unsigned Type)
Prio = ConstExpression ();
if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
/* Value out of range */
Error ("Range error");
Error ("Given priority is out of range");
return;
}
} else {
@@ -333,7 +336,7 @@ static StrBuf* GenArrayType (StrBuf* Type, unsigned SpanSize,
static void DoA16 (void)
/* Switch the accu to 16 bit mode (assembler only) */
{
if (GetCPU() != CPU_65816) {
if (GetCPU () != CPU_65816) {
Error ("Command is only valid in 65816 mode");
} else {
/* Immidiate mode has two extension bytes */
@@ -346,7 +349,7 @@ static void DoA16 (void)
static void DoA8 (void)
/* Switch the accu to 8 bit mode (assembler only) */
{
if (GetCPU() != CPU_65816) {
if (GetCPU () != CPU_65816) {
Error ("Command is only valid in 65816 mode");
} else {
/* Immidiate mode has one extension byte */
@@ -400,7 +403,7 @@ static void DoAlign (void)
/* Read the alignment value */
Alignment = ConstExpression ();
if (Alignment <= 0 || (unsigned long) Alignment > MAX_ALIGNMENT) {
ErrorSkip ("Range error");
ErrorSkip ("Alignment is out of range");
return;
}
@@ -410,7 +413,7 @@ static void DoAlign (void)
FillVal = ConstExpression ();
/* We need a byte value here */
if (!IsByteRange (FillVal)) {
ErrorSkip ("Range error");
ErrorSkip ("Fill value is not in byte range");
return;
}
} else {
@@ -428,8 +431,7 @@ static void DoASCIIZ (void)
{
while (1) {
/* Must have a string constant */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
if (!ExpectSkip (TOK_STRCON, "Expected a string constant")) {
return;
}
@@ -463,11 +465,10 @@ static void DoAssert (void)
/* First we have the expression that has to evaluated */
ExprNode* Expr = Expression ();
ConsumeComma ();
/* Action follows */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
/* Followed by comma and action */
if (!ConsumeComma () || !Expect (TOK_IDENT, "Expected an identifier")) {
SkipUntilSep ();
return;
}
switch (GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]))) {
@@ -496,9 +497,8 @@ static void DoAssert (void)
default:
Error ("Illegal assert action specifier");
/* Use lderror - there won't be an .o file anyway */
Action = ASSERT_ACT_LDERROR;
break;
SkipUntilSep ();
return;
}
NextTok ();
@@ -512,8 +512,7 @@ static void DoAssert (void)
NextTok ();
/* Read the message */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
if (!ExpectSkip (TOK_STRCON, "Expected a string constant")) {
return;
}
@@ -642,20 +641,23 @@ static void DoCharMap (void)
/* Read the index as numerical value */
Index = ConstExpression ();
if (Index < 0 || Index > 255) {
if (IsByteRange (Index)) {
/* Value out of range */
ErrorSkip ("Index range error");
ErrorSkip ("Index must be in byte range");
return;
}
/* Comma follows */
ConsumeComma ();
if (!ConsumeComma ()) {
SkipUntilSep ();
return;
}
/* Read the character code */
Code = ConstExpression ();
if (Code < 0 || Code > 255) {
if (!IsByteRange (Code)) {
/* Value out of range */
ErrorSkip ("Code range error");
ErrorSkip ("Replacement character code must be in byte range");
return;
}
@@ -685,15 +687,17 @@ static void DoConDes (void)
long Type;
/* Symbol name follows */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
if (!ExpectSkip (TOK_IDENT, "Expected an identifier")) {
return;
}
SB_Copy (&Name, &CurTok.SVal);
NextTok ();
/* Type follows. May be encoded as identifier or numerical */
ConsumeComma ();
if (!ConsumeComma ()) {
SkipUntilSep ();
goto ExitPoint;
}
if (CurTok.Tok == TOK_IDENT) {
/* Map the following keyword to a number, then skip it */
@@ -702,7 +706,8 @@ static void DoConDes (void)
/* Check if we got a valid keyword */
if (Type < 0) {
ErrorSkip ("Syntax error");
ErrorExpect ("Expected CONSTRUCTOR, DESTRUCTOR or INTERRUPTOR");
SkipUntilSep ();
goto ExitPoint;
}
@@ -712,7 +717,7 @@ static void DoConDes (void)
Type = ConstExpression ();
if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
/* Value out of range */
ErrorSkip ("Range error");
ErrorSkip ("Numeric condes type is out of range");
goto ExitPoint;
}
@@ -734,8 +739,7 @@ static void DoConstructor (void)
StrBuf Name = STATIC_STRBUF_INITIALIZER;
/* Symbol name follows */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
if (!ExpectSkip (TOK_IDENT, "Expected an identifier")) {
return;
}
SB_Copy (&Name, &CurTok.SVal);
@@ -771,8 +775,7 @@ static void DoDbg (void)
/* We expect a subkey */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
if (!ExpectSkip (TOK_IDENT, "Expected an identifier")) {
return;
}
@@ -788,7 +791,10 @@ static void DoDbg (void)
case 1: DbgInfoFunc (); break;
case 2: DbgInfoLine (); break;
case 3: DbgInfoSym (); break;
default: ErrorSkip ("Syntax error"); break;
default:
ErrorExpect ("Expected FILE, FUNC, LINE or SYM");
SkipUntilSep ();
break;
}
}
@@ -853,9 +859,7 @@ static void DoDelMac (void)
/* Delete a classic macro */
{
/* We expect an identifier */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
} else {
if (ExpectSkip (TOK_IDENT, "Expected an identifier")) {
MacUndef (&CurTok.SVal, MAC_STYLE_CLASSIC);
NextTok ();
}
@@ -869,8 +873,7 @@ static void DoDestructor (void)
StrBuf Name = STATIC_STRBUF_INITIALIZER;
/* Symbol name follows */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
if (!ExpectSkip (TOK_IDENT, "Expected an identifier")) {
return;
}
SB_Copy (&Name, &CurTok.SVal);
@@ -938,9 +941,7 @@ static void DoEndScope (void)
static void DoError (void)
/* User error */
{
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
if (ExpectSkip (TOK_STRCON, "Expected a string constant")) {
Error ("User error: %m%p", &CurTok.SVal);
SkipUntilSep ();
}
@@ -1010,9 +1011,7 @@ static void DoFarAddr (void)
static void DoFatal (void)
/* Fatal user error */
{
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
if (ExpectSkip (TOK_STRCON, "Expected a string constant")) {
Fatal ("User error: %m%p", &CurTok.SVal);
SkipUntilSep ();
}
@@ -1030,14 +1029,13 @@ static void DoFeature (void)
while (1) {
/* We expect an identifier */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
if (!ExpectSkip (TOK_IDENT, "Expected an identifier")) {
return;
}
/* Make the string attribute lower case */
LocaseSVal ();
Feature = FindFeature(&CurTok.SVal);
Feature = FindFeature (&CurTok.SVal);
if (Feature == FEAT_UNKNOWN) {
/* Not found */
ErrorSkip ("Invalid feature: '%m%p'", &CurTok.SVal);
@@ -1045,7 +1043,8 @@ static void DoFeature (void)
}
if (Feature == FEAT_ADDRSIZE) {
Warning (1, "Deprecated feature: '.feature addrsize'. Pseudo function .addrsize is always available.");
Warning (1, "Deprecated feature: '.feature addrsize'. "
"Pseudo function .addrsize is always available.");
}
NextTok ();
@@ -1053,7 +1052,7 @@ static void DoFeature (void)
/* Optional +/- or ON/OFF */
On = 1;
if (CurTok.Tok != TOK_COMMA && !TokIsSep (CurTok.Tok)) {
SetBoolOption(&On);
SetBoolOption (&On);
}
/* Apply feature setting. */
@@ -1087,19 +1086,17 @@ static void DoFileOpt (void)
OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
if (OptNum < 0) {
/* Not found */
ErrorSkip ("File option keyword expected");
ErrorExpect ("Expected a file option keyword");
SkipUntilSep ();
return;
}
/* Skip the keyword */
NextTok ();
/* Must be followed by a comma */
ConsumeComma ();
/* We accept only string options for now */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
/* Must be followed by a comma and a string option */
if (!ConsumeComma () || !Expect (TOK_STRCON, "Expected a string constant")) {
SkipUntilSep ();
return;
}
@@ -1134,16 +1131,13 @@ static void DoFileOpt (void)
/* Option given as number */
OptNum = ConstExpression ();
if (!IsByteRange (OptNum)) {
ErrorSkip ("Range error");
ErrorSkip ("Option number must be in byte range");
return;
}
/* Must be followed by a comma */
ConsumeComma ();
/* We accept only string options for now */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
/* Must be followed by a comma plus a string constant */
if (!ConsumeComma () || !Expect (TOK_STRCON, "Expected a string constant")) {
SkipUntilSep ();
return;
}
@@ -1198,7 +1192,7 @@ static void DoHiBytes (void)
static void DoI16 (void)
/* Switch the index registers to 16 bit mode (assembler only) */
{
if (GetCPU() != CPU_65816) {
if (GetCPU () != CPU_65816) {
Error ("Command is only valid in 65816 mode");
} else {
/* Immidiate mode has two extension bytes */
@@ -1211,7 +1205,7 @@ static void DoI16 (void)
static void DoI8 (void)
/* Switch the index registers to 16 bit mode (assembler only) */
{
if (GetCPU() != CPU_65816) {
if (GetCPU () != CPU_65816) {
Error ("Command is only valid in 65816 mode");
} else {
/* Immidiate mode has one extension byte */
@@ -1248,8 +1242,7 @@ static void DoIncBin (void)
FILE* F;
/* Name must follow */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
if (!ExpectSkip (TOK_STRCON, "Expected a string constant")) {
return;
}
SB_Copy (&Name, &CurTok.SVal);
@@ -1314,13 +1307,16 @@ static void DoIncBin (void)
Count = Size - Start;
if (Count < 0) {
/* Nothing to read - flag this as a range error */
ErrorSkip ("Range error");
ErrorSkip ("Start offset is larger than file size");
goto Done;
}
} else {
/* Count was given, check if it is valid */
if (Start + Count > Size) {
ErrorSkip ("Range error");
if (Start > Size) {
ErrorSkip ("Start offset is larger than file size");
goto Done;
} else if (Start + Count > Size) {
ErrorSkip ("Not enough bytes left in file at offset %ld", Start);
goto Done;
}
}
@@ -1367,9 +1363,7 @@ static void DoInclude (void)
/* Include another file */
{
/* Name must follow */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
if (ExpectSkip (TOK_STRCON, "Expected a string constant")) {
SB_Terminate (&CurTok.SVal);
if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) {
/* Error opening the file, skip remainder of line */
@@ -1386,8 +1380,7 @@ static void DoInterruptor (void)
StrBuf Name = STATIC_STRBUF_INITIALIZER;
/* Symbol name follows */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
if (!ExpectSkip (TOK_IDENT, "Expected an identifier")) {
return;
}
SB_Copy (&Name, &CurTok.SVal);
@@ -1474,9 +1467,7 @@ static void DoListBytes (void)
static void DoLocalChar (void)
/* Define the character that starts local labels */
{
if (CurTok.Tok != TOK_CHARCON) {
ErrorSkip ("Character constant expected");
} else {
if (ExpectSkip (TOK_CHARCON, "Expected a character constant")) {
if (CurTok.IVal != '@' && CurTok.IVal != '?') {
Error ("Invalid start character for locals");
} else {
@@ -1492,15 +1483,14 @@ static void DoMacPack (void)
/* Insert a macro package */
{
/* We expect an identifier */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
} else {
SB_AppendStr (&CurTok.SVal, ".mac");
SB_Terminate (&CurTok.SVal);
if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) {
/* Error opening the file, skip remainder of line */
SkipUntilSep ();
}
if (!ExpectSkip (TOK_IDENT, "Expected an identifier")) {
return;
}
SB_AppendStr (&CurTok.SVal, ".mac");
SB_Terminate (&CurTok.SVal);
if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) {
/* Error opening the file, skip remainder of line */
SkipUntilSep ();
}
}
@@ -1538,12 +1528,10 @@ static void DoOrg (void)
static void DoOut (void)
/* Output a string */
{
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
if (ExpectSkip (TOK_STRCON, "Expected a string constant")) {
/* Output the string and be sure to flush the output to keep it in
** sync with any error messages if the output is redirected to a file.
*/
* sync with any error messages if the output is redirected to a file.
*/
printf ("%.*s\n",
(int) SB_GetLen (&CurTok.SVal),
SB_GetConstBuf (&CurTok.SVal));
@@ -1835,7 +1823,7 @@ static void DoRes (void)
Count = ConstExpression ();
if (Count > 0xFFFF || Count < 0) {
ErrorSkip ("Range error");
ErrorSkip ("Invalid number of bytes specified");
return;
}
if (CurTok.Tok == TOK_COMMA) {
@@ -1843,7 +1831,7 @@ static void DoRes (void)
Val = ConstExpression ();
/* We need a byte value here */
if (!IsByteRange (Val)) {
ErrorSkip ("Range error");
ErrorSkip ("Fill value is not in byte range");
return;
}
@@ -1903,12 +1891,10 @@ static void DoScope (void)
static void DoSegment (void)
/* Switch to another segment */
{
StrBuf Name = STATIC_STRBUF_INITIALIZER;
SegDef Def;
if (ExpectSkip (TOK_STRCON, "Expected a string constant")) {
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
SegDef Def;
StrBuf Name = AUTO_STRBUF_INITIALIZER;
/* Save the name of the segment and skip it */
SB_Copy (&Name, &CurTok.SVal);
@@ -1923,10 +1909,10 @@ static void DoSegment (void)
/* Set the segment */
UseSeg (&Def);
}
/* Free memory for Name */
SB_Done (&Name);
/* Free memory for Name */
SB_Done (&Name);
}
}
@@ -1935,9 +1921,7 @@ static void DoSetCPU (void)
/* Switch the CPU instruction set */
{
/* We expect an identifier */
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
if (ExpectSkip (TOK_STRCON, "Expected a string constant")) {
cpu_t CPU;
/* Try to find the CPU */
@@ -1948,8 +1932,8 @@ static void DoSetCPU (void)
SetCPU (CPU);
/* Skip the identifier. If the CPU switch was successful, the scanner
** will treat the input now correctly for the new CPU.
*/
* will treat the input now correctly for the new CPU.
*/
NextTok ();
}
}
@@ -2024,9 +2008,7 @@ static void DoUnDef (void)
EnableDefineStyleMacros ();
/* We expect an identifier */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
} else {
if (ExpectSkip (TOK_IDENT, "Expected an identifier")) {
MacUndef (&CurTok.SVal, MAC_STYLE_DEFINE);
NextTok ();
}
@@ -2046,9 +2028,7 @@ static void DoUnexpected (void)
static void DoWarning (void)
/* User warning */
{
if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
if (ExpectSkip (TOK_STRCON, "Expected a string constant")) {
Warning (0, "User warning: %m%p", &CurTok.SVal);
SkipUntilSep ();
}

View File

@@ -120,7 +120,7 @@ void ParseRepeat (void)
/* Repeat count follows */
long RepCount = ConstExpression ();
if (RepCount < 0) {
Error ("Range error");
Error ("Repeat count must be positive or zero");
RepCount = 0;
}
@@ -132,9 +132,7 @@ void ParseRepeat (void)
NextTok ();
/* Check for an identifier */
if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
} else {
if (ExpectSkip (TOK_IDENT, "Expected an identifier")) {
/* Remember the name and skip it */
SB_Terminate (&CurTok.SVal);
Name = xstrdup (SB_GetConstBuf (&CurTok.SVal));

View File

@@ -818,7 +818,7 @@ static void ReadStringConst (int StringTerm)
int Cooked = 1;
NeedNext = 1;
if (StringTerm == 0 && SB_GetLen(&CurTok.SVal) == 1) {
if (StringTerm == 0 && SB_GetLen (&CurTok.SVal) == 1) {
if (C == '\'') {
break;
}
@@ -901,12 +901,12 @@ static void ReadStringConst (int StringTerm)
case '7':
{ /* brace needed for scoping */
int Count = 1;
int Final = DigitVal(C);
int Final = DigitVal (C);
Cooked = 0;
NextChar ();
while (IsODigit (C) && Count++ < 3) {
Final = (Final << 3) | DigitVal(C);
NextChar();
Final = (Final << 3) | DigitVal (C);
NextChar ();
}
if (C >= 256)
Error ("Octal character constant out of range");
@@ -1587,8 +1587,8 @@ CharAgain:
/* Always a character constant
** Hack: Pass 0 to ReadStringConst for special handling.
*/
ReadStringConst(0);
if (SB_GetLen(&CurTok.SVal) != 1) {
ReadStringConst (0);
if (SB_GetLen (&CurTok.SVal) != 1) {
Error ("Illegal character constant");
goto CharAgain;
}

View File

@@ -105,14 +105,21 @@ static long DoStructInternal (long Offs, unsigned Type)
** union, the struct may be anonymous; in which case, no new lexical level
** is started.
*/
int Anon = (CurTok.Tok != TOK_IDENT);
int Anon = (CurTok.Tok == TOK_SEP);
if (!Anon) {
/* Enter a new scope, then skip the name */
SymEnterLevel (&CurTok.SVal, SCOPE_STRUCT, ADDR_SIZE_ABS, 0);
NextTok ();
/* Start at zero offset in the new scope */
Offs = 0;
/* Non anonymous structs must have an identifier as name */
if (Expect (TOK_IDENT, "Expected a struct/union name")) {
/* Enter a new scope, then skip the name */
SymEnterLevel (&CurTok.SVal, SCOPE_STRUCT, ADDR_SIZE_ABS, 0);
NextTok ();
/* Start at zero offset in the new scope */
Offs = 0;
} else {
/* Skip the junk on the line before proceeding */
SkipUntilSep ();
Anon = 1;
}
}
/* Test for end of line */
@@ -183,7 +190,7 @@ static long DoStructInternal (long Offs, unsigned Type)
case TOK_RES:
NextTok ();
if (CurTok.Tok == TOK_SEP) {
ErrorSkip ("Size is missing");
ErrorExpect ("Expected a byte count");
} else {
MemberSize = Member (1);
}
@@ -192,7 +199,7 @@ static long DoStructInternal (long Offs, unsigned Type)
case TOK_ORG:
NextTok ();
if (CurTok.Tok == TOK_SEP) {
ErrorSkip ("Address is missing");
ErrorExpect ("Expected an address");
} else {
Offs = ConstExpression ();
@@ -233,7 +240,12 @@ static long DoStructInternal (long Offs, unsigned Type)
default:
if (!CheckConditionals ()) {
/* Not a conditional directive */
ErrorSkip ("Invalid storage allocator in struct/union");
if (Sym) {
ErrorExpect ("Expected a storage allocator after the field name");
} else {
ErrorExpect ("Expected a storage allocator");
}
SkipUntilSep ();
}
}
@@ -275,9 +287,9 @@ static long DoStructInternal (long Offs, unsigned Type)
/* End of struct/union definition */
if (Type == STRUCT) {
Consume (TOK_ENDSTRUCT, "'.ENDSTRUCT' expected");
Consume (TOK_ENDSTRUCT, "Expected '.ENDSTRUCT'");
} else {
Consume (TOK_ENDUNION, "'.ENDUNION' expected");
Consume (TOK_ENDUNION, "Expected '.ENDUNION'");
}
/* Return the size of the struct */

View File

@@ -1359,8 +1359,7 @@ static void StudyNearAddr (ExprNode* Expr, ExprDesc* D)
}
/* Promote to absolute if smaller. */
if (D->AddrSize < ADDR_SIZE_ABS)
{
if (D->AddrSize < ADDR_SIZE_ABS) {
D->AddrSize = ADDR_SIZE_ABS;
}
}

View File

@@ -73,7 +73,7 @@ SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
/* Start from the root scope */
Scope = RootScope;
} else if (CurTok.Tok == TOK_IDENT) {
} else if (Expect (TOK_IDENT, "Expected an identifier")) {
/* Remember the name and skip it */
SB_Copy (Name, &CurTok.SVal);
@@ -115,8 +115,7 @@ SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
while (1) {
/* Next token must be an identifier. */
if (CurTok.Tok != TOK_IDENT) {
Error ("Identifier expected");
if (!Expect (TOK_IDENT, "Expected an identifier")) {
return 0;
}

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

View File

@@ -53,76 +53,80 @@
/* Tokens */
typedef enum token_t {
TOK_NONE, /* Start value, invalid */
TOK_EOF, /* End of input file */
TOK_SEP, /* Separator (usually newline) */
TOK_IDENT, /* An identifier */
TOK_LOCAL_IDENT, /* A cheap local identifier */
TOK_NONE, /* Start value, invalid */
TOK_EOF, /* End of input file */
TOK_SEP, /* Separator (usually newline) */
TOK_IDENT, /* An identifier */
TOK_LOCAL_IDENT, /* A cheap local identifier */
TOK_INTCON, /* Integer constant */
TOK_CHARCON, /* Character constant */
TOK_STRCON, /* String constant */
TOK_INTCON, /* Integer constant */
TOK_CHARCON, /* Character constant */
TOK_STRCON, /* String constant */
TOK_A, /* A)ccumulator */
TOK_X, /* X register */
TOK_Y, /* Y register */
TOK_Z, /* Z register */
TOK_S, /* S register */
TOK_Q, /* Q pseudo register */
TOK_REG, /* Sweet16 R.. register (in sweet16 mode) */
TOK_FIRSTREG, /* First register name token */
TOK_A = TOK_FIRSTREG, /* A)ccumulator */
TOK_Q, /* Q pseudo register */
TOK_S, /* S register */
TOK_X, /* X register */
TOK_Y, /* Y register */
TOK_Z, /* Z register */
TOK_REG, /* Sweet16 R.. register (in sweet16 mode) */
TOK_LASTREG = TOK_REG, /* Last register name token */
TOK_ASSIGN, /* := */
TOK_ULABEL, /* An unnamed label */
TOK_ASSIGN, /* := */
TOK_ULABEL, /* An unnamed label */
TOK_EQ, /* = */
TOK_NE, /* <> */
TOK_LT, /* < */
TOK_GT, /* > */
TOK_LE, /* <= */
TOK_GE, /* >= */
TOK_FIRSTOP, /* First operator token */
TOK_EQ = TOK_FIRSTOP, /* = */
TOK_NE, /* <> */
TOK_LT, /* < */
TOK_GT, /* > */
TOK_LE, /* <= */
TOK_GE, /* >= */
TOK_BOOLAND, /* .and */
TOK_BOOLOR, /* .or */
TOK_BOOLXOR, /* .xor */
TOK_BOOLNOT, /* .not */
TOK_BOOLAND, /* .and */
TOK_BOOLOR, /* .or */
TOK_BOOLXOR, /* .xor */
TOK_BOOLNOT, /* .not */
TOK_PLUS, /* + */
TOK_MINUS, /* - */
TOK_MUL, /* * */
TOK_STAR = TOK_MUL, /* Alias */
TOK_DIV, /* / */
TOK_MOD, /* ! */
TOK_OR, /* | */
TOK_XOR, /* ^ */
TOK_AND, /* & */
TOK_SHL, /* << */
TOK_SHR, /* >> */
TOK_NOT, /* ~ */
TOK_PLUS, /* + */
TOK_MINUS, /* - */
TOK_MUL, /* * */
TOK_STAR = TOK_MUL, /* Alias */
TOK_DIV, /* / */
TOK_MOD, /* ! */
TOK_OR, /* | */
TOK_XOR, /* ^ */
TOK_AND, /* & */
TOK_SHL, /* << */
TOK_SHR, /* >> */
TOK_NOT, /* ~ */
TOK_LASTOP = TOK_NOT, /* Last operator token */
TOK_PC, /* $ if enabled */
TOK_NAMESPACE, /* :: */
TOK_DOT, /* . */
TOK_COMMA, /* , */
TOK_HASH, /* # */
TOK_COLON, /* : */
TOK_LPAREN, /* ( */
TOK_RPAREN, /* ) */
TOK_LBRACK, /* [ */
TOK_RBRACK, /* ] */
TOK_LCURLY, /* { */
TOK_RCURLY, /* } */
TOK_AT, /* @ - in Sweet16 mode */
TOK_PC, /* $ if enabled */
TOK_NAMESPACE, /* :: */
TOK_DOT, /* . */
TOK_COMMA, /* , */
TOK_HASH, /* # */
TOK_COLON, /* : */
TOK_LPAREN, /* ( */
TOK_RPAREN, /* ) */
TOK_LBRACK, /* [ */
TOK_RBRACK, /* ] */
TOK_LCURLY, /* { */
TOK_RCURLY, /* } */
TOK_AT, /* @ - in Sweet16 mode */
TOK_OVERRIDE_ZP, /* z: */
TOK_OVERRIDE_ABS, /* a: */
TOK_OVERRIDE_FAR, /* f: */
TOK_OVERRIDE_ZP, /* z: */
TOK_OVERRIDE_ABS, /* a: */
TOK_OVERRIDE_FAR, /* f: */
TOK_MACPARAM, /* Macro parameter, not generated by scanner */
TOK_REPCOUNTER, /* Repeat counter, not generated by scanner */
TOK_MACPARAM, /* Macro parameter, not generated by scanner */
TOK_REPCOUNTER, /* Repeat counter, not generated by scanner */
/* The next ones are tokens for the pseudo instructions. Keep together! */
TOK_FIRSTPSEUDO,
TOK_A16 = TOK_FIRSTPSEUDO,
TOK_A16 = TOK_FIRSTPSEUDO,
TOK_A8,
TOK_ADDR,
TOK_ADDRSIZE,
@@ -284,9 +288,9 @@ typedef enum token_t {
TOK_WORD,
TOK_XMATCH,
TOK_ZEROPAGE,
TOK_LASTPSEUDO = TOK_ZEROPAGE,
TOK_LASTPSEUDO = TOK_ZEROPAGE,
TOK_COUNT /* Count of tokens */
TOK_COUNT /* Count of tokens */
} token_t;
@@ -318,11 +322,27 @@ struct Token {
int TokHasSVal (token_t Tok);
#if defined(HAVE_INLINE)
INLINE 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);
}
#else
# define TokHasIVal(T) \
((T) == TOK_IDENT || (T) == TOK_LOCAL_IDENT || (T) == TOK_STRCON)
#endif
int TokHasIVal (token_t Tok);
#if defined(HAVE_INLINE)
INLINE 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);
}
#else
# define TokHasIVal(T) \
((T) == TOK_INTCON || (T) == TOK_CHARCON || (T) == TOK_REG)
#endif
#if defined(HAVE_INLINE)
INLINE int TokIsSep (enum token_t T)
@@ -339,6 +359,9 @@ void CopyToken (Token* Dst, const Token* Src);
** initialized.
*/
StrBuf* TokenDesc (const Token* T, StrBuf* S);
/* Place a textual description of the given token into S. */
/* End of token.h */

View File

@@ -111,7 +111,7 @@ ExprNode* ULabRef (int Which)
if (Which == 0) {
Error ("Invalid unnamed label reference");
/* We must return something valid */
return GenCurrentPC();
return GenCurrentPC ();
}
/* Get the index of the referenced label */
@@ -125,7 +125,7 @@ ExprNode* ULabRef (int Which)
/* Label does not exist */
Error ("Undefined label");
/* We must return something valid */
return GenCurrentPC();
return GenCurrentPC ();
}
/* Check if the label exists. If not, generate enough forward labels. */

View File

@@ -1,6 +1,4 @@
.macpack cpu
; step 1: try to assemble an instruction that's exclusive to this set
; (when possible)

View File

@@ -0,0 +1 @@
0:

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,3 @@
.struct x
.word
.endstruct

View File

@@ -0,0 +1 @@
lda #$00 foo

View File

@@ -0,0 +1 @@
lda ($00),a

View File

@@ -0,0 +1 @@
lda ($00,a)

View File

@@ -0,0 +1,3 @@
.struct foo
bar
.endstruct

View File

@@ -0,0 +1 @@
127

View File

@@ -0,0 +1 @@
.fileopt author

View File

@@ -0,0 +1 @@
.assert 1

View File

@@ -0,0 +1,2 @@
lda |

View File

@@ -0,0 +1 @@
.byte 0 1

View File

@@ -1,6 +1,6 @@
110-capabilities.s:3: Error: Arguments to .CAPABILITY must be identifiers
110-capabilities.s:8: Error: Arguments to .CAPABILITY must be identifiers
110-capabilities.s:8: Error: ')' expected
110-capabilities.s:3: Error: Expected a capability name but found ')'
110-capabilities.s:8: Error: Expected a capability name but found 'end-of-line'
110-capabilities.s:8: Error: Expected ')' but found 'end-of-line'
110-capabilities.s:12: Error: Not a valid capability name: CPU_HAS_BR
110-capabilities.s:17: Error: ')' expected
110-capabilities.s:17: Error: Unexpected trailing garbage characters
110-capabilities.s:17: Error: Expected ')' but found 'cpu_has_bra8'
110-capabilities.s:17: Error: Expected 'end-of-line' but found 'cpu_has_bra8'

View File

@@ -0,0 +1 @@
120-errormsg.s:1: Error: Expected 'end-of-line' but found '0'

View File

@@ -0,0 +1 @@
121-errormsg.s:1: Error: Expected ':' after identifier to form a label but found 'end-of-line'

View File

@@ -0,0 +1 @@
122-errormsg.s:1: Error: Expected a struct/union name but found 'X'

View File

@@ -0,0 +1 @@
123-errormsg.s:1: Error: Expected 'end-of-line' but found 'foo'

View File

@@ -0,0 +1 @@
124-errormsg.s:1: Error: Expected 'Y' but found 'A'

View File

@@ -0,0 +1,2 @@
125-errormsg.s:1: Error: Expected 'X' or 'S' but found 'A'
125-errormsg.s:1: Error: Illegal addressing mode

View File

@@ -0,0 +1 @@
126-errormsg.s:2: Error: Expected a storage allocator after the field name but found 'end-of-line'

View File

@@ -0,0 +1 @@
127-errormsg.s:1: Error: Expected a mnemonic but found '127'

View File

@@ -0,0 +1 @@
128-errormsg.s:1: Error: Expected ',' but found 'end-of-line'

View File

@@ -0,0 +1 @@
129-errormsg.s:1: Error: Expected ',' but found 'end-of-line'

View File

@@ -0,0 +1,2 @@
130-errormsg.s:1: Error: Expected an expression but found '|'
130-errormsg.s:1: Error: Expected an expression but found 'end-of-line'

View File

@@ -0,0 +1 @@
131-errormsg.s:1: Error: Expected 'end-of-line' but found '1'