Merge branch 'master' into macexpand

This commit is contained in:
Bob Andrews
2025-06-12 22:18:06 +02:00
committed by GitHub
546 changed files with 26846 additions and 7083 deletions

View File

@@ -133,24 +133,26 @@ static void SetIfCond (IfDesc* ID, int C)
static void ElseClause (IfDesc* ID, const char* Directive)
/* Enter an .ELSE clause */
static int ElseClause (IfDesc* ID, const char* Directive)
/* Enter an .ELSE clause. Return true if this was ok, zero on errors. */
{
/* Check if we have an open .IF - otherwise .ELSE is not allowed */
if (ID == 0) {
Error ("Unexpected %s", Directive);
return;
return 0;
}
/* Check for a duplicate else, then remember that we had one */
if (ID->Flags & ifElse) {
/* We already had a .ELSE ! */
Error ("Duplicate .ELSE");
return 0;
}
ID->Flags |= ifElse;
/* Condition is inverted now */
ID->Flags ^= ifCond;
return 1;
}
@@ -226,46 +228,52 @@ void DoConditionals (void)
D = GetCurrentIf ();
/* Allow an .ELSE */
ElseClause (D, ".ELSE");
if (ElseClause (D, ".ELSE")) {
/* Remember the data for the .ELSE */
if (D) {
ReleaseFullLineInfo (&D->LineInfos);
GetFullLineInfo (&D->LineInfos);
D->Name = ".ELSE";
}
/* Remember the data for the .ELSE */
if (D) {
ReleaseFullLineInfo (&D->LineInfos);
GetFullLineInfo (&D->LineInfos);
D->Name = ".ELSE";
/* Calculate the new overall condition */
CalcOverallIfCond ();
/* Skip .ELSE */
NextTok ();
ExpectSep ();
} else {
/* Problem with .ELSE, ignore remainder of line */
SkipUntilSep ();
}
/* Calculate the new overall condition */
CalcOverallIfCond ();
/* Skip .ELSE */
NextTok ();
ExpectSep ();
break;
case TOK_ELSEIF:
D = GetCurrentIf ();
/* Handle as if there was an .ELSE first */
ElseClause (D, ".ELSEIF");
if (ElseClause (D, ".ELSEIF")) {
/* Calculate the new overall if condition */
CalcOverallIfCond ();
/* Calculate the new overall if condition */
CalcOverallIfCond ();
/* Allocate and prepare a new descriptor */
D = AllocIf (".ELSEIF", 0);
NextTok ();
/* Allocate and prepare a new descriptor */
D = AllocIf (".ELSEIF", 0);
NextTok ();
/* Ignore the new condition if we are inside a false .ELSE
** branch. This way we won't get any errors about undefined
** symbols or similar...
*/
if (IfCond) {
SetIfCond (D, ConstExpression ());
ExpectSep ();
}
/* Ignore the new condition if we are inside a false .ELSE
** branch. This way we won't get any errors about undefined
** symbols or similar...
*/
if (IfCond) {
SetIfCond (D, ConstExpression ());
ExpectSep ();
/* Get the new overall condition */
CalcOverallIfCond ();
} else {
/* Problem with .ELSEIF, ignore remainder of line */
SkipUntilSep ();
}
/* Get the new overall condition */
CalcOverallIfCond ();
break;
case TOK_ENDIF:

View File

@@ -67,6 +67,7 @@ static const char* const FeatureKeys[FEAT_COUNT] = {
"bracket_as_indirect",
"string_escapes",
"long_jsr_jmp_rts",
"line_continuations",
};
@@ -121,6 +122,7 @@ void SetFeature (feature_t Feature, unsigned char On)
case FEAT_BRACKET_AS_INDIRECT: BracketAsIndirect = On; break;
case FEAT_STRING_ESCAPES: StringEscapes = On; break;
case FEAT_LONG_JSR_JMP_RTS: LongJsrJmpRts = On; break;
case FEAT_LINE_CONTINUATIONS: LineCont = On; break;
default: break;
}
}

View File

@@ -69,6 +69,7 @@ typedef enum {
FEAT_BRACKET_AS_INDIRECT,
FEAT_STRING_ESCAPES,
FEAT_LONG_JSR_JMP_RTS,
FEAT_LINE_CONTINUATIONS,
/* Special value: Number of features available */
FEAT_COUNT

View File

@@ -169,6 +169,7 @@ static const struct {
unsigned Count;
InsDesc Ins[56];
} InsTab6502 = {
/* CAUTION: table must be sorted for bsearch */
sizeof (InsTab6502.Ins) / sizeof (InsTab6502.Ins[0]),
{
{ "ADC", 0x080A26C, 0x60, 0, PutAll },
@@ -235,6 +236,7 @@ static const struct {
unsigned Count;
InsDesc Ins[75];
} InsTab6502X = {
/* CAUTION: table must be sorted for bsearch */
sizeof (InsTab6502X.Ins) / sizeof (InsTab6502X.Ins[0]),
{
{ "ADC", 0x080A26C, 0x60, 0, PutAll },
@@ -324,6 +326,7 @@ static const struct {
unsigned Count;
InsDesc Ins[71];
} InsTab6502DTV = {
/* CAUTION: table must be sorted for bsearch */
sizeof (InsTab6502DTV.Ins) / sizeof (InsTab6502DTV.Ins[0]),
{
{ "ADC", 0x080A26C, 0x60, 0, PutAll },
@@ -405,6 +408,7 @@ static const struct {
unsigned Count;
InsDesc Ins[66];
} InsTab65SC02 = {
/* CAUTION: table must be sorted for bsearch */
sizeof (InsTab65SC02.Ins) / sizeof (InsTab65SC02.Ins[0]),
{
{ "ADC", 0x080A66C, 0x60, 0, PutAll },
@@ -481,6 +485,7 @@ static const struct {
unsigned Count;
InsDesc Ins[100];
} InsTab65C02 = {
/* CAUTION: table must be sorted for bsearch */
sizeof (InsTab65C02.Ins) / sizeof (InsTab65C02.Ins[0]),
{
{ "ADC", 0x080A66C, 0x60, 0, PutAll },
@@ -591,6 +596,7 @@ static const struct {
unsigned Count;
InsDesc Ins[133];
} InsTab4510 = {
/* CAUTION: table must be sorted for bsearch */
sizeof (InsTab4510.Ins) / sizeof (InsTab4510.Ins[0]),
{
{ "ADC", 0x080A66C, 0x60, 0, PutAll },
@@ -734,6 +740,7 @@ static const struct {
unsigned Count;
InsDesc Ins[100];
} InsTab65816 = {
/* CAUTION: table must be sorted for bsearch */
sizeof (InsTab65816.Ins) / sizeof (InsTab65816.Ins[0]),
{
{ "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
@@ -844,6 +851,7 @@ static const struct {
unsigned Count;
InsDesc Ins[26];
} InsTabSweet16 = {
/* CAUTION: table must be sorted for bsearch */
sizeof (InsTabSweet16.Ins) / sizeof (InsTabSweet16.Ins[0]),
{
{ "ADD", AMSW16_REG, 0xA0, 0, PutSweet16 },
@@ -880,6 +888,7 @@ static const struct {
unsigned Count;
InsDesc Ins[135];
} InsTabHuC6280 = {
/* CAUTION: table must be sorted for bsearch */
sizeof (InsTabHuC6280.Ins) / sizeof (InsTabHuC6280.Ins[0]),
{
{ "ADC", 0x080A66C, 0x60, 0, PutAll },

View File

@@ -162,3 +162,28 @@ unsigned GetStackDepth (void)
{
return ICount;
}
InputStack RetrieveInputStack (void)
/* Retrieve the current input stack. This will also clear it. Used when
** including a file. The current input stack is stored together with the old
** input file and restored when the file is closed.
*/
{
/* We do not touch the counter so input sources are counted across
** includes.
*/
InputStack S = IStack;
IStack = 0;
return S;
}
void RestoreInputStack (InputStack S)
/* Restore an old input stack that was retrieved by RetrieveInputStack(). */
{
CHECK (IStack == 0);
IStack = S;
}

View File

@@ -38,6 +38,17 @@
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Opaque pointer to an input stack */
typedef void* InputStack;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
@@ -63,8 +74,20 @@ void CheckInputStack (void);
** stuff on the input stack.
*/
unsigned GetStackDepth (void);
InputStack RetrieveInputStack (void);
/* Retrieve the current input stack. This will also clear it. Used when
** including a file. The current input stack is stored together with the old
** input file and restored when the file is closed.
*/
void RestoreInputStack (InputStack S);
/* Restore an old input stack that was retrieved by RetrieveInputStack(). */
/* End of istack.h */
#endif

View File

@@ -719,6 +719,24 @@ static void OneLine (void)
NextTok ();
}
/* Handle @-style unnamed labels */
if (CurTok.Tok == TOK_ULABEL) {
if (CurTok.IVal != 0) {
Error ("Invalid unnamed label definition");
}
ULabDef ();
NextTok ();
/* Skip the colon. If NoColonLabels is enabled, allow labels without
** a colon if there is no whitespace before the identifier.
*/
if (CurTok.Tok == TOK_COLON) {
NextTok ();
} else if (CurTok.WS || !NoColonLabels) {
Error ("':' expected");
}
}
/* If the first token on the line is an identifier, check for a macro or
** an instruction.
*/

View File

@@ -46,6 +46,7 @@
#include "check.h"
#include "filestat.h"
#include "fname.h"
#include "tgttrans.h"
#include "xmalloc.h"
/* ca65 */
@@ -113,6 +114,7 @@ struct CharSource {
token_t Tok; /* Last token */
int C; /* Last character */
int SkipN; /* For '\r\n' line endings, skip '\n\ if next */
InputStack IStack; /* Saved input stack */
const CharSourceFunctions* Func; /* Pointer to function table */
union {
InputFile File; /* File data */
@@ -129,6 +131,7 @@ static int C = 0; /* Current input character */
int ForcedEnd = 0;
/* List of dot keywords with the corresponding tokens */
/* CAUTION: table must be sorted for bsearch */
struct DotKeyword {
const char* Key; /* MUST be first field */
token_t Tok;
@@ -321,6 +324,9 @@ static void UseCharSource (CharSource* S)
S->Tok = CurTok.Tok;
S->C = C;
/* Remember the current input stack */
S->IStack = RetrieveInputStack ();
/* Use the new input source */
S->Next = Source;
Source = S;
@@ -347,7 +353,10 @@ static void DoneCharSource (void)
/* Restore the old token */
CurTok.Tok = Source->Tok;
C = Source->C;
C = Source->C;
/* Restore the old input source */
RestoreInputStack (Source->IStack);
/* Remember the last stacked input source */
S = Source->Next;
@@ -792,14 +801,33 @@ static void ReadIdent (void)
static void ReadStringConst (int StringTerm)
/* Read a string constant into SVal. */
{
int NeedNext;
/* Skip the leading string terminator */
NextChar ();
/* Read the string */
while (1) {
int Cooked = 1;
NeedNext = 1;
if (StringTerm == 0 && SB_GetLen(&CurTok.SVal) == 1) {
if (C == '\'') {
break;
}
else if (MissingCharTerm) {
NeedNext = 0;
break;
}
else {
Error ("Illegal character constant");
}
}
if (C == StringTerm) {
break;
}
if (C == '\n' || C == EOF) {
Error ("Newline in string constant");
break;
@@ -812,20 +840,74 @@ static void ReadStringConst (int StringTerm)
case EOF:
Error ("Unterminated escape sequence in string constant");
break;
case '\\':
case '\'':
case '"':
case '?':
C = '\?';
break;
case 't':
C = '\x09';
case 'a':
C = '\a';
break;
case 'b':
C = '\b';
break;
case 'e':
C = '\x1B'; /* see comments in cc65/scanner.c */
break;
case 'f':
C = '\f';
break;
case 'r':
C = '\x0D';
C = '\r';
break;
case 'n':
C = '\x0A';
C = '\n';
break;
case 't':
C = '\t';
break;
case 'v':
C = '\v';
break;
case '\\':
C = '\\'; /* unnecessary but more readable */
break;
case '\'':
C = '\''; /* unnecessary but more readable */
if (StringTerm == 0) {
/* special case used by character constants
** when LooseStringTerm not set. this will
** cause '\' to be a valid character constant
*/
C = '\\';
NeedNext = 0;
}
break;
case '\"':
C = '\"'; /* unnecessary but more readable */
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
{ /* brace needed for scoping */
int Count = 1;
int Final = DigitVal(C);
Cooked = 0;
NextChar ();
while (IsODigit (C) && Count++ < 3) {
Final = (Final << 3) | DigitVal(C);
NextChar();
}
if (C >= 256)
Error ("Octal character constant out of range");
}
break;
case 'X':
case 'x':
Cooked = 0;
NextChar ();
if (IsXDigit (C)) {
char high_nibble = DigitVal (C) << 4;
@@ -843,14 +925,19 @@ static void ReadStringConst (int StringTerm)
}
/* Append the char to the string */
SB_AppendChar (&CurTok.SVal, C);
SB_AppendCharCooked (&CurTok.SVal, C, Cooked);
/* Skip the character */
NextChar ();
if (NeedNext) {
/* Skip the character */
NextChar ();
NeedNext = 1;
}
}
/* Skip the trailing terminator */
NextChar ();
if (NeedNext) {
/* Skip the trailing terminator */
NextChar ();
}
/* Terminate the string */
SB_Terminate (&CurTok.SVal);
@@ -1135,17 +1222,33 @@ Again:
/* Local symbol? */
if (C == LocalStart) {
/* Read the identifier. */
ReadIdent ();
NextChar ();
/* Start character alone is not enough */
if (SB_GetLen (&CurTok.SVal) == 1) {
Error ("Invalid cheap local symbol");
goto Again;
if (IsIdChar (C)) {
/* Read a local identifier */
CurTok.Tok = TOK_LOCAL_IDENT;
SB_AppendChar (&CurTok.SVal, LocalStart);
ReadIdent ();
} else {
/* Read an unnamed label */
CurTok.IVal = 0;
CurTok.Tok = TOK_ULABEL;
if (C == '-' || C == '<') {
int PrevC = C;
do {
--CurTok.IVal;
NextChar ();
} while (C == PrevC);
} else if (C == '+' || C == '>') {
int PrevC = C;
do {
++CurTok.IVal;
NextChar ();
} while (C == PrevC);
}
}
/* A local identifier */
CurTok.Tok = TOK_LOCAL_IDENT;
return;
}
@@ -1325,22 +1428,30 @@ CharAgain:
break;
case '-':
case '<':
{
int PrevC = C;
CurTok.IVal = 0;
do {
--CurTok.IVal;
NextChar ();
} while (C == '-');
} while (C == PrevC);
CurTok.Tok = TOK_ULABEL;
break;
}
case '+':
case '>':
{
int PrevC = C;
CurTok.IVal = 0;
do {
++CurTok.IVal;
NextChar ();
} while (C == '+');
} while (C == PrevC);
CurTok.Tok = TOK_ULABEL;
break;
}
case '=':
NextChar ();
@@ -1445,11 +1556,11 @@ CharAgain:
return;
case '\'':
/* Hack: If we allow ' as terminating character for strings, read
** the following stuff as a string, and check for a one character
** string later.
*/
if (LooseStringTerm) {
/* Hack: If we allow ' as terminating character for strings, read
** the following stuff as a string, and check for a one character
** string later.
*/
ReadStringConst ('\'');
if (SB_GetLen (&CurTok.SVal) == 1) {
CurTok.IVal = SB_AtUnchecked (&CurTok.SVal, 0);
@@ -1458,22 +1569,16 @@ CharAgain:
CurTok.Tok = TOK_STRCON;
}
} else {
/* Always a character constant */
NextChar ();
if (C == EOF || IsControl (C)) {
/* Always a character constant
** Hack: Pass 0 to ReadStringConst for special handling.
*/
ReadStringConst(0);
if (SB_GetLen(&CurTok.SVal) != 1) {
Error ("Illegal character constant");
goto CharAgain;
}
CurTok.IVal = C;
CurTok.IVal = SB_AtUnchecked (&CurTok.SVal, 0);
CurTok.Tok = TOK_CHARCON;
NextChar ();
if (C != '\'') {
if (!MissingCharTerm) {
Error ("Illegal character constant");
}
} else {
NextChar ();
}
}
return;
@@ -1508,7 +1613,7 @@ CharAgain:
/* In case of the main file, do not close it, but return EOF. */
if (Source && Source->Next) {
DoneCharSource ();
goto Again;
goto Restart;
} else {
CurTok.Tok = TOK_EOF;
}

View File

@@ -71,7 +71,7 @@ typedef enum token_t {
TOK_REG, /* Sweet16 R.. register (in sweet16 mode) */
TOK_ASSIGN, /* := */
TOK_ULABEL, /* :++ or :-- */
TOK_ULABEL, /* An unnamed label */
TOK_EQ, /* = */
TOK_NE, /* <> */

View File

@@ -107,8 +107,12 @@ ExprNode* ULabRef (int Which)
int Index;
ULabel* L;
/* Which can never be 0 */
PRECONDITION (Which != 0);
/* Which should not be 0 */
if (Which == 0) {
Error ("Invalid unnamed label reference");
/* We must return something valid */
return GenCurrentPC();
}
/* Get the index of the referenced label */
if (Which > 0) {