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:
@@ -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 ();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
147
src/ca65/token.h
147
src/ca65/token.h
@@ -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 */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
|
||||
.macpack cpu
|
||||
|
||||
; step 1: try to assemble an instruction that's exclusive to this set
|
||||
; (when possible)
|
||||
|
||||
|
||||
1
test/asm/listing/120-errormsg.s
Normal file
1
test/asm/listing/120-errormsg.s
Normal file
@@ -0,0 +1 @@
|
||||
0:
|
||||
1
test/asm/listing/121-errormsg.s
Normal file
1
test/asm/listing/121-errormsg.s
Normal file
@@ -0,0 +1 @@
|
||||
foo
|
||||
3
test/asm/listing/122-errormsg.s
Normal file
3
test/asm/listing/122-errormsg.s
Normal file
@@ -0,0 +1,3 @@
|
||||
.struct x
|
||||
.word
|
||||
.endstruct
|
||||
1
test/asm/listing/123-errormsg.s
Normal file
1
test/asm/listing/123-errormsg.s
Normal file
@@ -0,0 +1 @@
|
||||
lda #$00 foo
|
||||
1
test/asm/listing/124-errormsg.s
Normal file
1
test/asm/listing/124-errormsg.s
Normal file
@@ -0,0 +1 @@
|
||||
lda ($00),a
|
||||
1
test/asm/listing/125-errormsg.s
Normal file
1
test/asm/listing/125-errormsg.s
Normal file
@@ -0,0 +1 @@
|
||||
lda ($00,a)
|
||||
3
test/asm/listing/126-errormsg.s
Normal file
3
test/asm/listing/126-errormsg.s
Normal file
@@ -0,0 +1,3 @@
|
||||
.struct foo
|
||||
bar
|
||||
.endstruct
|
||||
1
test/asm/listing/127-errormsg.s
Normal file
1
test/asm/listing/127-errormsg.s
Normal file
@@ -0,0 +1 @@
|
||||
127
|
||||
1
test/asm/listing/128-errormsg.s
Normal file
1
test/asm/listing/128-errormsg.s
Normal file
@@ -0,0 +1 @@
|
||||
.fileopt author
|
||||
1
test/asm/listing/129-errormsg.s
Normal file
1
test/asm/listing/129-errormsg.s
Normal file
@@ -0,0 +1 @@
|
||||
.assert 1
|
||||
2
test/asm/listing/130-errormsg.s
Normal file
2
test/asm/listing/130-errormsg.s
Normal file
@@ -0,0 +1,2 @@
|
||||
lda |
|
||||
|
||||
1
test/asm/listing/131-errormsg.s
Normal file
1
test/asm/listing/131-errormsg.s
Normal file
@@ -0,0 +1 @@
|
||||
.byte 0 1
|
||||
@@ -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'
|
||||
|
||||
1
test/asm/listing/ref/120-errormsg.err2
Normal file
1
test/asm/listing/ref/120-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
120-errormsg.s:1: Error: Expected 'end-of-line' but found '0'
|
||||
1
test/asm/listing/ref/121-errormsg.err2
Normal file
1
test/asm/listing/ref/121-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
121-errormsg.s:1: Error: Expected ':' after identifier to form a label but found 'end-of-line'
|
||||
1
test/asm/listing/ref/122-errormsg.err2
Normal file
1
test/asm/listing/ref/122-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
122-errormsg.s:1: Error: Expected a struct/union name but found 'X'
|
||||
1
test/asm/listing/ref/123-errormsg.err2
Normal file
1
test/asm/listing/ref/123-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
123-errormsg.s:1: Error: Expected 'end-of-line' but found 'foo'
|
||||
1
test/asm/listing/ref/124-errormsg.err2
Normal file
1
test/asm/listing/ref/124-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
124-errormsg.s:1: Error: Expected 'Y' but found 'A'
|
||||
2
test/asm/listing/ref/125-errormsg.err2
Normal file
2
test/asm/listing/ref/125-errormsg.err2
Normal 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
|
||||
1
test/asm/listing/ref/126-errormsg.err2
Normal file
1
test/asm/listing/ref/126-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
126-errormsg.s:2: Error: Expected a storage allocator after the field name but found 'end-of-line'
|
||||
1
test/asm/listing/ref/127-errormsg.err2
Normal file
1
test/asm/listing/ref/127-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
127-errormsg.s:1: Error: Expected a mnemonic but found '127'
|
||||
1
test/asm/listing/ref/128-errormsg.err2
Normal file
1
test/asm/listing/ref/128-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
128-errormsg.s:1: Error: Expected ',' but found 'end-of-line'
|
||||
1
test/asm/listing/ref/129-errormsg.err2
Normal file
1
test/asm/listing/ref/129-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
129-errormsg.s:1: Error: Expected ',' but found 'end-of-line'
|
||||
2
test/asm/listing/ref/130-errormsg.err2
Normal file
2
test/asm/listing/ref/130-errormsg.err2
Normal 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'
|
||||
1
test/asm/listing/ref/131-errormsg.err2
Normal file
1
test/asm/listing/ref/131-errormsg.err2
Normal file
@@ -0,0 +1 @@
|
||||
131-errormsg.s:1: Error: Expected 'end-of-line' but found '1'
|
||||
Reference in New Issue
Block a user