Merge pull request #2785 from kugelfuhr/kugelfuhr/modernize-ca65-diags
Modernize ca65 diagnostics
This commit is contained in:
@@ -106,6 +106,7 @@ Short options:
|
|||||||
Long options:
|
Long options:
|
||||||
--auto-import Mark unresolved symbols as import
|
--auto-import Mark unresolved symbols as import
|
||||||
--bin-include-dir dir Set a search path for binary includes
|
--bin-include-dir dir Set a search path for binary includes
|
||||||
|
--color [on|auto|off] Color diagnostics (default: auto)
|
||||||
--cpu type Set cpu type
|
--cpu type Set cpu type
|
||||||
--create-dep name Create a make dependency file
|
--create-dep name Create a make dependency file
|
||||||
--create-full-dep name Create a full make dependency file
|
--create-full-dep name Create a full make dependency file
|
||||||
@@ -119,8 +120,9 @@ Long options:
|
|||||||
--listing name Create a listing file if assembly was ok
|
--listing name Create a listing file if assembly was ok
|
||||||
--list-bytes n Maximum number of bytes per listing line
|
--list-bytes n Maximum number of bytes per listing line
|
||||||
--memory-model model Set the memory model
|
--memory-model model Set the memory model
|
||||||
|
--no-utf8 Disable use of UTF-8 in diagnostics
|
||||||
--pagelength n Set the page length for the listing
|
--pagelength n Set the page length for the listing
|
||||||
--relax-checks Disables some error checks
|
--relax-checks Relax some checks (see docs)
|
||||||
--smart Enable smart mode
|
--smart Enable smart mode
|
||||||
--target sys Set the target system
|
--target sys Set the target system
|
||||||
--verbose Increase verbosity
|
--verbose Increase verbosity
|
||||||
@@ -146,6 +148,14 @@ Here is a description of all the command line options:
|
|||||||
name="search paths">.
|
name="search paths">.
|
||||||
|
|
||||||
|
|
||||||
|
<label id="option--color">
|
||||||
|
<tag><tt>--color</tt></tag>
|
||||||
|
|
||||||
|
This option controls if the assembler will use colors when printing
|
||||||
|
diagnostics. The default is "auto" which will enable colors if the output
|
||||||
|
goes to a terminal (not to a file).
|
||||||
|
|
||||||
|
|
||||||
<label id="option--cpu">
|
<label id="option--cpu">
|
||||||
<tag><tt>--cpu type</tt></tag>
|
<tag><tt>--cpu type</tt></tag>
|
||||||
|
|
||||||
@@ -259,6 +269,14 @@ Here is a description of all the command line options:
|
|||||||
huge.
|
huge.
|
||||||
|
|
||||||
|
|
||||||
|
<label id="option--no-utf8">
|
||||||
|
<tag><tt>--no-utf8</tt></tag>
|
||||||
|
|
||||||
|
Disable the use of UTF-8 characters in diagnostics. This might be necessary
|
||||||
|
if auto detection fails or if the output is captured for processing with a
|
||||||
|
tool that is not UTF-8 capable.
|
||||||
|
|
||||||
|
|
||||||
<label id="option-o">
|
<label id="option-o">
|
||||||
<tag><tt>-o name</tt></tag>
|
<tag><tt>-o name</tt></tag>
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@
|
|||||||
<ClInclude Include="ca65\easw16.h" />
|
<ClInclude Include="ca65\easw16.h" />
|
||||||
<ClInclude Include="ca65\enum.h" />
|
<ClInclude Include="ca65\enum.h" />
|
||||||
<ClInclude Include="ca65\error.h" />
|
<ClInclude Include="ca65\error.h" />
|
||||||
|
<ClInclude Include="ca65\expect.h" />
|
||||||
<ClInclude Include="ca65\expr.h" />
|
<ClInclude Include="ca65\expr.h" />
|
||||||
<ClInclude Include="ca65\feature.h" />
|
<ClInclude Include="ca65\feature.h" />
|
||||||
<ClInclude Include="ca65\filetab.h" />
|
<ClInclude Include="ca65\filetab.h" />
|
||||||
@@ -132,6 +133,7 @@
|
|||||||
<ClCompile Include="ca65\easw16.c" />
|
<ClCompile Include="ca65\easw16.c" />
|
||||||
<ClCompile Include="ca65\enum.c" />
|
<ClCompile Include="ca65\enum.c" />
|
||||||
<ClCompile Include="ca65\error.c" />
|
<ClCompile Include="ca65\error.c" />
|
||||||
|
<ClCompile Include="ca65\expect.c" />
|
||||||
<ClCompile Include="ca65\expr.c" />
|
<ClCompile Include="ca65\expr.c" />
|
||||||
<ClCompile Include="ca65\feature.c" />
|
<ClCompile Include="ca65\feature.c" />
|
||||||
<ClCompile Include="ca65\filetab.c" />
|
<ClCompile Include="ca65\filetab.c" />
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "instr.h"
|
#include "instr.h"
|
||||||
#include "lineinfo.h"
|
#include "lineinfo.h"
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "dbginfo.h"
|
#include "dbginfo.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "filetab.h"
|
#include "filetab.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
@@ -462,7 +463,7 @@ void DbgInfoCheck (void)
|
|||||||
/* Search for the symbol name */
|
/* Search for the symbol name */
|
||||||
S->Sym = SymFindAny (S->Scope, GetStrBuf (S->AsmName));
|
S->Sym = SymFindAny (S->Scope, GetStrBuf (S->AsmName));
|
||||||
if (S->Sym == 0) {
|
if (S->Sym == 0) {
|
||||||
PError (&S->Pos, "Assembler symbol '%s' not found",
|
PError (&S->Pos, "Assembler symbol `%s' not found",
|
||||||
GetString (S->AsmName));
|
GetString (S->AsmName));
|
||||||
} else {
|
} else {
|
||||||
/* Set the backlink */
|
/* Set the backlink */
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "ea.h"
|
#include "ea.h"
|
||||||
#include "ea65.h"
|
#include "ea65.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "instr.h"
|
#include "instr.h"
|
||||||
#include "nexttok.h"
|
#include "nexttok.h"
|
||||||
@@ -62,11 +63,11 @@ void GetEA (EffAddr* A)
|
|||||||
if (BracketAsIndirect) {
|
if (BracketAsIndirect) {
|
||||||
IndirectEnter = TOK_LBRACK;
|
IndirectEnter = TOK_LBRACK;
|
||||||
IndirectLeave = TOK_RBRACK;
|
IndirectLeave = TOK_RBRACK;
|
||||||
IndirectExpect = "Expected ']'";
|
IndirectExpect = "Expected `]'";
|
||||||
} else {
|
} else {
|
||||||
IndirectEnter = TOK_LPAREN;
|
IndirectEnter = TOK_LPAREN;
|
||||||
IndirectLeave = TOK_RPAREN;
|
IndirectLeave = TOK_RPAREN;
|
||||||
IndirectExpect = "Expected ')'";
|
IndirectExpect = "Expected `)'";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the output struct */
|
/* Clear the output struct */
|
||||||
@@ -145,12 +146,12 @@ void GetEA (EffAddr* A)
|
|||||||
A->AddrModeSet = AM65_STACK_REL_IND_Y;
|
A->AddrModeSet = AM65_STACK_REL_IND_Y;
|
||||||
if (!Consume (IndirectLeave, IndirectExpect) ||
|
if (!Consume (IndirectLeave, IndirectExpect) ||
|
||||||
!ConsumeComma () ||
|
!ConsumeComma () ||
|
||||||
!Consume (TOK_Y, "Expected 'Y'")) {
|
!Consume (TOK_Y, "Expected `Y'")) {
|
||||||
/* In case of errors skip anything else on the line */
|
/* In case of errors skip anything else on the line */
|
||||||
SkipUntilSep ();
|
SkipUntilSep ();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ErrorExpect ("Expected 'X' or 'S'");
|
ErrorExpect ("Expected `X' or `S'");
|
||||||
SkipUntilSep ();
|
SkipUntilSep ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +169,7 @@ void GetEA (EffAddr* A)
|
|||||||
A->AddrModeSet = AM65_DIR_IND;
|
A->AddrModeSet = AM65_DIR_IND;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!Consume (TOK_Y, "Expected 'Y'")) {
|
if (!Consume (TOK_Y, "Expected `Y'")) {
|
||||||
SkipUntilSep ();
|
SkipUntilSep ();
|
||||||
}
|
}
|
||||||
A->AddrModeSet = AM65_DIR_IND_Y;
|
A->AddrModeSet = AM65_DIR_IND_Y;
|
||||||
@@ -198,20 +199,20 @@ void GetEA (EffAddr* A)
|
|||||||
/* [dir] or [dir],y */
|
/* [dir] or [dir],y */
|
||||||
NextTok ();
|
NextTok ();
|
||||||
A->Expr = Expression ();
|
A->Expr = Expression ();
|
||||||
if (!Consume (TOK_RBRACK, "Expected ']'")) {
|
if (!Consume (TOK_RBRACK, "Expected `]'")) {
|
||||||
SkipUntilSep ();
|
SkipUntilSep ();
|
||||||
}
|
}
|
||||||
if (CurTok.Tok == TOK_COMMA) {
|
if (CurTok.Tok == TOK_COMMA) {
|
||||||
/* [dir],y */
|
/* [dir],y */
|
||||||
NextTok ();
|
NextTok ();
|
||||||
if (GetCPU () == CPU_45GS02) {
|
if (GetCPU () == CPU_45GS02) {
|
||||||
if (!Consume (TOK_Z, "Expected 'Z'")) {
|
if (!Consume (TOK_Z, "Expected `Z'")) {
|
||||||
SkipUntilSep ();
|
SkipUntilSep ();
|
||||||
}
|
}
|
||||||
A->AddrModeSet = AM65_32BIT_BASE_IND_Z;
|
A->AddrModeSet = AM65_32BIT_BASE_IND_Z;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!Consume (TOK_Y, "Expected 'Y'")) {
|
if (!Consume (TOK_Y, "Expected `Y'")) {
|
||||||
SkipUntilSep ();
|
SkipUntilSep ();
|
||||||
}
|
}
|
||||||
A->AddrModeSet = AM65_DIR_IND_LONG_Y;
|
A->AddrModeSet = AM65_DIR_IND_LONG_Y;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "ea.h"
|
#include "ea.h"
|
||||||
#include "ea65.h"
|
#include "ea65.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "instr.h"
|
#include "instr.h"
|
||||||
#include "nexttok.h"
|
#include "nexttok.h"
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#include "condasm.h"
|
#include "condasm.h"
|
||||||
#include "enum.h"
|
#include "enum.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "nexttok.h"
|
#include "nexttok.h"
|
||||||
@@ -147,7 +148,7 @@ void DoEnum (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* End of enum definition */
|
/* End of enum definition */
|
||||||
Consume (TOK_ENDENUM, "'.ENDENUM' expected");
|
Consume (TOK_ENDENUM, "`.ENDENUM' expected");
|
||||||
|
|
||||||
/* Free the base expression */
|
/* Free the base expression */
|
||||||
FreeExpr (BaseExpr);
|
FreeExpr (BaseExpr);
|
||||||
|
|||||||
188
src/ca65/error.c
188
src/ca65/error.c
@@ -38,6 +38,8 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
/* common */
|
/* common */
|
||||||
|
#include "cmdline.h"
|
||||||
|
#include "consprop.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
|
|
||||||
/* ca65 */
|
/* ca65 */
|
||||||
@@ -45,6 +47,7 @@
|
|||||||
#include "filetab.h"
|
#include "filetab.h"
|
||||||
#include "lineinfo.h"
|
#include "lineinfo.h"
|
||||||
#include "nexttok.h"
|
#include "nexttok.h"
|
||||||
|
#include "spool.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -64,6 +67,14 @@ unsigned WarningCount = 0;
|
|||||||
/* Maximum number of additional notifications */
|
/* Maximum number of additional notifications */
|
||||||
#define MAX_NOTES 8
|
#define MAX_NOTES 8
|
||||||
|
|
||||||
|
/* Diagnostic category */
|
||||||
|
typedef enum { DC_NOTE, DC_WARN, DC_ERR, DC_FATAL, DC_COUNT } DiagCat;
|
||||||
|
|
||||||
|
/* Descriptions for diagnostic categories */
|
||||||
|
const char* DiagCatDesc[DC_COUNT] = {
|
||||||
|
"Note", "Warning", "Error", "Fatal error"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -72,27 +83,144 @@ unsigned WarningCount = 0;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void VPrintMsg (const FilePos* Pos, const char* Desc,
|
static void ReplaceQuotes (StrBuf* Msg)
|
||||||
const char* Format, va_list ap)
|
/* Replace opening and closing single quotes in Msg by their typographically
|
||||||
|
** correct UTF-8 counterparts for better readbility. A closing quote will
|
||||||
|
** only get replaced if an opening quote has been seen before.
|
||||||
|
** To handle some special cases, the function will also treat \xF0 as
|
||||||
|
** opening and \xF1 as closing quote. These are replaced without the need for
|
||||||
|
** correct ordering (open/close).
|
||||||
|
** The function will change the quotes in place, so after the call Msg will
|
||||||
|
** contain the changed string. If UTF-8 is not available, the function will
|
||||||
|
** replace '`' by '\'' since that was the default behavior before. It will
|
||||||
|
** also replace \xF0 and \xF1 by '\''.
|
||||||
|
**/
|
||||||
|
{
|
||||||
|
/* UTF-8 characters for single quotes */
|
||||||
|
static const char QuoteStart[] = "\xE2\x80\x98";
|
||||||
|
static const char QuoteEnd[] = "\xE2\x80\x99";
|
||||||
|
|
||||||
|
/* ANSI color sequences */
|
||||||
|
const char* ColorStart = CP_BrightGreen ();
|
||||||
|
const char* ColorEnd = CP_White ();
|
||||||
|
|
||||||
|
/* Remember a few things */
|
||||||
|
int IsUTF8 = CP_IsUTF8 ();
|
||||||
|
|
||||||
|
/* We create a new string in T and will later copy it back to Msg */
|
||||||
|
StrBuf T = AUTO_STRBUF_INITIALIZER;
|
||||||
|
|
||||||
|
/* Parse the string and create a modified copy */
|
||||||
|
SB_Reset (Msg);
|
||||||
|
int InQuote = 0;
|
||||||
|
while (1) {
|
||||||
|
char C = SB_Get (Msg);
|
||||||
|
switch (C) {
|
||||||
|
case '`':
|
||||||
|
if (!InQuote) {
|
||||||
|
InQuote = 1;
|
||||||
|
if (IsUTF8) {
|
||||||
|
SB_AppendStr (&T, QuoteStart);
|
||||||
|
} else {
|
||||||
|
/* ca65 uses \' for opening and closing quotes */
|
||||||
|
SB_AppendChar (&T, '\'');
|
||||||
|
}
|
||||||
|
SB_AppendStr (&T, ColorStart);
|
||||||
|
} else {
|
||||||
|
/* Found two ` without closing quote - don't replace */
|
||||||
|
SB_AppendChar (&T, '`');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
if (InQuote) {
|
||||||
|
InQuote = 0;
|
||||||
|
SB_AppendStr (&T, ColorEnd);
|
||||||
|
if (IsUTF8) {
|
||||||
|
SB_AppendStr (&T, QuoteEnd);
|
||||||
|
} else {
|
||||||
|
SB_AppendChar (&T, C);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SB_AppendChar (&T, C);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\xF0':
|
||||||
|
if (IsUTF8) {
|
||||||
|
SB_AppendStr (&T, QuoteStart);
|
||||||
|
} else {
|
||||||
|
SB_AppendChar (&T, '\'');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\xF1':
|
||||||
|
if (IsUTF8) {
|
||||||
|
SB_AppendStr (&T, QuoteEnd);
|
||||||
|
} else {
|
||||||
|
SB_AppendChar (&T, '\'');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
goto Done;
|
||||||
|
default:
|
||||||
|
SB_AppendChar (&T, C);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
/* Copy the string back, then terminate it */
|
||||||
|
SB_Move (Msg, &T);
|
||||||
|
SB_Terminate (Msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void VPrintMsg (const FilePos* Pos, DiagCat Cat, const char* Format,
|
||||||
|
va_list ap)
|
||||||
/* Format and output an error/warning message. */
|
/* Format and output an error/warning message. */
|
||||||
{
|
{
|
||||||
StrBuf S = STATIC_STRBUF_INITIALIZER;
|
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||||
|
StrBuf Msg = AUTO_STRBUF_INITIALIZER;
|
||||||
|
StrBuf Loc = AUTO_STRBUF_INITIALIZER;
|
||||||
|
|
||||||
/* Format the actual message */
|
/* Determine the description for the category and its color */
|
||||||
StrBuf Msg = STATIC_STRBUF_INITIALIZER;
|
const char* Desc = DiagCatDesc[Cat];
|
||||||
|
const char* Color;
|
||||||
|
switch (Cat) {
|
||||||
|
case DC_NOTE: Color = CP_Cyan (); break;
|
||||||
|
case DC_WARN: Color = CP_Yellow (); break;
|
||||||
|
case DC_ERR: Color = CP_BrightRed (); break;
|
||||||
|
case DC_FATAL: Color = CP_BrightRed (); break;
|
||||||
|
default: FAIL ("Unexpected Cat value"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format the actual message, then replace quotes */
|
||||||
SB_VPrintf (&Msg, Format, ap);
|
SB_VPrintf (&Msg, Format, ap);
|
||||||
SB_Terminate (&Msg);
|
ReplaceQuotes (&Msg);
|
||||||
|
|
||||||
/* Format the message header */
|
/* Format the location. If the file position is valid, we use the file
|
||||||
SB_Printf (&S, "%s:%u: %s: ",
|
** position, otherwise the program name. This allows to print fatal
|
||||||
SB_GetConstBuf (GetFileName (Pos->Name)),
|
** errors in the startup phase.
|
||||||
Pos->Line,
|
*/
|
||||||
Desc);
|
if (Pos->Name == EMPTY_STRING_ID) {
|
||||||
|
SB_CopyStr (&Loc, ProgName);
|
||||||
|
} else {
|
||||||
|
SB_Printf (&Loc, "%s:%u", SB_GetConstBuf (GetFileName (Pos->Name)),
|
||||||
|
Pos->Line);
|
||||||
|
}
|
||||||
|
SB_Terminate (&Loc);
|
||||||
|
|
||||||
/* Append the message to the message header */
|
/* Format the full message */
|
||||||
SB_Append (&S, &Msg);
|
SB_Printf (&S, "%s%s: %s%s:%s %s%s",
|
||||||
|
CP_White (),
|
||||||
|
SB_GetConstBuf (&Loc),
|
||||||
|
Color,
|
||||||
|
Desc,
|
||||||
|
CP_White (),
|
||||||
|
SB_GetConstBuf (&Msg),
|
||||||
|
CP_Reset ());
|
||||||
|
|
||||||
/* Delete the formatted message */
|
/* Delete the formatted message and the location string */
|
||||||
|
SB_Done (&Loc);
|
||||||
SB_Done (&Msg);
|
SB_Done (&Msg);
|
||||||
|
|
||||||
/* Add a new line and terminate the generated full message */
|
/* Add a new line and terminate the generated full message */
|
||||||
@@ -177,13 +305,25 @@ static void AddNotifications (const Collection* LineInfos)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Notification (const char* Format, ...)
|
||||||
|
/* Print a notification message. */
|
||||||
|
{
|
||||||
|
/* Output the message */
|
||||||
|
va_list ap;
|
||||||
|
va_start (ap, Format);
|
||||||
|
VPrintMsg (&CurTok.Pos, DC_NOTE, Format, ap);
|
||||||
|
va_end (ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PNotification (const FilePos* Pos, const char* Format, ...)
|
void PNotification (const FilePos* Pos, const char* Format, ...)
|
||||||
/* Print a notification message. */
|
/* Print a notification message. */
|
||||||
{
|
{
|
||||||
/* Output the message */
|
/* Output the message */
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start (ap, Format);
|
va_start (ap, Format);
|
||||||
VPrintMsg (Pos, "Note", Format, ap);
|
VPrintMsg (Pos, DC_NOTE, Format, ap);
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +342,7 @@ static void WarningMsg (const Collection* LineInfos, const char* Format, va_list
|
|||||||
const LineInfo* LI = CollConstAt (LineInfos, 0);
|
const LineInfo* LI = CollConstAt (LineInfos, 0);
|
||||||
|
|
||||||
/* Output a warning for this position */
|
/* Output a warning for this position */
|
||||||
VPrintMsg (GetSourcePos (LI), "Warning", Format, ap);
|
VPrintMsg (GetSourcePos (LI), DC_WARN, Format, ap);
|
||||||
|
|
||||||
/* Add additional notifications if necessary */
|
/* Add additional notifications if necessary */
|
||||||
AddNotifications (LineInfos);
|
AddNotifications (LineInfos);
|
||||||
@@ -243,7 +383,7 @@ void PWarning (const FilePos* Pos, unsigned Level, const char* Format, ...)
|
|||||||
if (Level <= WarnLevel) {
|
if (Level <= WarnLevel) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start (ap, Format);
|
va_start (ap, Format);
|
||||||
VPrintMsg (Pos, "Warning", Format, ap);
|
VPrintMsg (Pos, DC_WARN, Format, ap);
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
|
||||||
/* Count warnings */
|
/* Count warnings */
|
||||||
@@ -280,7 +420,7 @@ void ErrorMsg (const Collection* LineInfos, const char* Format, va_list ap)
|
|||||||
const LineInfo* LI = CollConstAt (LineInfos, 0);
|
const LineInfo* LI = CollConstAt (LineInfos, 0);
|
||||||
|
|
||||||
/* Output an error for this position */
|
/* Output an error for this position */
|
||||||
VPrintMsg (GetSourcePos (LI), "Error", Format, ap);
|
VPrintMsg (GetSourcePos (LI), DC_ERR, Format, ap);
|
||||||
|
|
||||||
/* Add additional notifications if necessary */
|
/* Add additional notifications if necessary */
|
||||||
AddNotifications (LineInfos);
|
AddNotifications (LineInfos);
|
||||||
@@ -317,7 +457,7 @@ void PError (const FilePos* Pos, const char* Format, ...)
|
|||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start (ap, Format);
|
va_start (ap, Format);
|
||||||
VPrintMsg (Pos, "Error", Format, ap);
|
VPrintMsg (Pos, DC_ERR, Format, ap);
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
|
||||||
/* Count errors */
|
/* Count errors */
|
||||||
@@ -371,18 +511,12 @@ void ErrorSkip (const char* Format, ...)
|
|||||||
void Fatal (const char* Format, ...)
|
void Fatal (const char* Format, ...)
|
||||||
/* Print a message about a fatal error and die */
|
/* Print a message about a fatal error and die */
|
||||||
{
|
{
|
||||||
|
/* Output the message ... */
|
||||||
va_list ap;
|
va_list ap;
|
||||||
StrBuf S = STATIC_STRBUF_INITIALIZER;
|
|
||||||
|
|
||||||
va_start (ap, Format);
|
va_start (ap, Format);
|
||||||
SB_VPrintf (&S, Format, ap);
|
VPrintMsg (&CurTok.Pos, DC_FATAL, Format, ap);
|
||||||
SB_Terminate (&S);
|
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
|
||||||
fprintf (stderr, "Fatal error: %s\n", SB_GetConstBuf (&S));
|
|
||||||
|
|
||||||
SB_Done (&S);
|
|
||||||
|
|
||||||
/* And die... */
|
/* And die... */
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ extern unsigned WarningCount;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Notification (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||||
|
/* Print a notification message. */
|
||||||
|
|
||||||
void PNotification (const FilePos* Pos, const char* Format, ...) attribute ((format (printf, 2, 3)));
|
void PNotification (const FilePos* Pos, const char* Format, ...) attribute ((format (printf, 2, 3)));
|
||||||
/* Print a notification message. */
|
/* Print a notification message. */
|
||||||
|
|
||||||
|
|||||||
116
src/ca65/expect.c
Normal file
116
src/ca65/expect.c
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* expect.c */
|
||||||
|
/* */
|
||||||
|
/* Print errors about expected tokens */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2025, Kugelfuhr */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ca65 */
|
||||||
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
|
#include "nexttok.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 then 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
|
||||||
|
* then 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 then 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 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)) {
|
||||||
|
/* Try to be helpful by giving information about the token that was
|
||||||
|
* unexpected.
|
||||||
|
*/
|
||||||
|
ErrorExpect ("Expected `end-of-line'");
|
||||||
|
SkipUntilSep ();
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
83
src/ca65/expect.h
Normal file
83
src/ca65/expect.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* expect.h */
|
||||||
|
/* */
|
||||||
|
/* Print errors about expected tokens */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2025, Kugelfuhr */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef EXPECT_H
|
||||||
|
#define EXPECT_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ca65 */
|
||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 then be
|
||||||
|
* "xyz expected but found zyx".
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
* then be "xyz expected but found zyx".
|
||||||
|
* Returns true if the token was found, otherwise false.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 then be "xyz expected but found
|
||||||
|
* zyx".
|
||||||
|
* Returns true if the token was found, otherwise false.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* End of expect.h */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -51,6 +51,7 @@
|
|||||||
|
|
||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "instr.h"
|
#include "instr.h"
|
||||||
@@ -778,7 +779,7 @@ static ExprNode* FuncAddrSize (void)
|
|||||||
/* Cheap local symbol */
|
/* Cheap local symbol */
|
||||||
Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
|
Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
|
||||||
if (Sym == 0) {
|
if (Sym == 0) {
|
||||||
Error ("Unknown symbol or scope: '%m%p'", &CurTok.SVal);
|
Error ("Unknown symbol or scope: `%m%p'", &CurTok.SVal);
|
||||||
} else {
|
} else {
|
||||||
AddrSize = Sym->AddrSize;
|
AddrSize = Sym->AddrSize;
|
||||||
}
|
}
|
||||||
@@ -818,13 +819,13 @@ static ExprNode* FuncAddrSize (void)
|
|||||||
if (Sym) {
|
if (Sym) {
|
||||||
AddrSize = Sym->AddrSize;
|
AddrSize = Sym->AddrSize;
|
||||||
} else {
|
} else {
|
||||||
Error ("Unknown symbol or scope: '%m%p%m%p'", &ScopeName, &Name);
|
Error ("Unknown symbol or scope: `%m%p%m%p'", &ScopeName, &Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AddrSize == 0) {
|
if (AddrSize == 0) {
|
||||||
Warning (1, "Unknown address size: '%m%p%m%p'", &ScopeName, &Name);
|
Warning (1, "Unknown address size: `%m%p%m%p'", &ScopeName, &Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free the string buffers */
|
/* Free the string buffers */
|
||||||
@@ -859,7 +860,7 @@ static ExprNode* FuncSizeOf (void)
|
|||||||
/* Cheap local symbol */
|
/* Cheap local symbol */
|
||||||
Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
|
Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
|
||||||
if (Sym == 0) {
|
if (Sym == 0) {
|
||||||
Error ("Unknown symbol or scope: '%m%p'", &CurTok.SVal);
|
Error ("Unknown symbol or scope: `%m%p'", &CurTok.SVal);
|
||||||
} else {
|
} else {
|
||||||
SizeSym = GetSizeOfSymbol (Sym);
|
SizeSym = GetSizeOfSymbol (Sym);
|
||||||
}
|
}
|
||||||
@@ -911,7 +912,7 @@ static ExprNode* FuncSizeOf (void)
|
|||||||
if (Sym) {
|
if (Sym) {
|
||||||
SizeSym = GetSizeOfSymbol (Sym);
|
SizeSym = GetSizeOfSymbol (Sym);
|
||||||
} else {
|
} else {
|
||||||
Error ("Unknown symbol or scope: '%m%p%m%p'",
|
Error ("Unknown symbol or scope: `%m%p%m%p'",
|
||||||
&ScopeName, &Name);
|
&ScopeName, &Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -919,7 +920,7 @@ static ExprNode* FuncSizeOf (void)
|
|||||||
|
|
||||||
/* Check if we have a size */
|
/* Check if we have a size */
|
||||||
if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
|
if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
|
||||||
Error ("Size of '%m%p%m%p' is unknown", &ScopeName, &Name);
|
Error ("Size of `%m%p%m%p' is unknown", &ScopeName, &Name);
|
||||||
Size = 0;
|
Size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1059,7 +1060,7 @@ static ExprNode* Function (ExprNode* (*F) (void))
|
|||||||
NextTok ();
|
NextTok ();
|
||||||
|
|
||||||
/* Expression must be enclosed in braces */
|
/* Expression must be enclosed in braces */
|
||||||
if (!ExpectSkip (TOK_LPAREN, "Expected '('")) {
|
if (!ExpectSkip (TOK_LPAREN, "Expected `('")) {
|
||||||
return GenLiteral0 ();
|
return GenLiteral0 ();
|
||||||
}
|
}
|
||||||
NextTok ();
|
NextTok ();
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ unsigned GetFileIndex (const StrBuf* Name)
|
|||||||
|
|
||||||
/* If we don't have this index, print a diagnostic and use the main file */
|
/* If we don't have this index, print a diagnostic and use the main file */
|
||||||
if (F == 0) {
|
if (F == 0) {
|
||||||
Error ("File name '%m%p' not found in file table", Name);
|
Error ("File name `%m%p' not found in file table", Name);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return F->Index;
|
return F->Index;
|
||||||
@@ -316,7 +316,7 @@ static void CreateDepFile (const char* Name, FileType Types)
|
|||||||
/* Open the file */
|
/* Open the file */
|
||||||
FILE* F = fopen (Name, "w");
|
FILE* F = fopen (Name, "w");
|
||||||
if (F == 0) {
|
if (F == 0) {
|
||||||
Fatal ("Cannot open dependency file '%s': %s", Name, strerror (errno));
|
Fatal ("Cannot open dependency file `%s': %s", Name, strerror (errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the output file followed by a tab char */
|
/* Print the output file followed by a tab char */
|
||||||
|
|||||||
@@ -1961,7 +1961,7 @@ static void PutLDM_m740 (const InsDesc* Ins)
|
|||||||
}
|
}
|
||||||
Emit0 (Ins->BaseCode);
|
Emit0 (Ins->BaseCode);
|
||||||
EmitByte (A.Expr);
|
EmitByte (A.Expr);
|
||||||
Consume (TOK_HASH, "'#' expected");
|
Consume (TOK_HASH, "`#' expected");
|
||||||
EmitByte (Expression ());
|
EmitByte (Expression ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ void CreateListing (void)
|
|||||||
/* Open the real listing file */
|
/* Open the real listing file */
|
||||||
F = fopen (SB_GetConstBuf (&ListingName), "w");
|
F = fopen (SB_GetConstBuf (&ListingName), "w");
|
||||||
if (F == 0) {
|
if (F == 0) {
|
||||||
Fatal ("Cannot open listing file '%s': %s",
|
Fatal ("Cannot open listing file `%s': %s",
|
||||||
SB_GetConstBuf (&ListingName),
|
SB_GetConstBuf (&ListingName),
|
||||||
strerror (errno));
|
strerror (errno));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "condasm.h"
|
#include "condasm.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "instr.h"
|
#include "instr.h"
|
||||||
#include "istack.h"
|
#include "istack.h"
|
||||||
@@ -380,7 +381,7 @@ static void MacSkipDef (unsigned Style, const FilePos* StartPos)
|
|||||||
int LastWasSep = 0;
|
int LastWasSep = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (CurTok.Tok == TOK_EOF) {
|
if (CurTok.Tok == TOK_EOF) {
|
||||||
ErrorExpect ("Expected '.ENDMACRO'");
|
ErrorExpect ("Expected `.ENDMACRO'");
|
||||||
PNotification (StartPos, "Macro definition started here");
|
PNotification (StartPos, "Macro definition started here");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -434,9 +435,9 @@ void MacDef (unsigned Style)
|
|||||||
Existing = HT_Find (&MacroTab, &CurTok.SVal);
|
Existing = HT_Find (&MacroTab, &CurTok.SVal);
|
||||||
if (Existing != 0) {
|
if (Existing != 0) {
|
||||||
/* Macro is already defined */
|
/* Macro is already defined */
|
||||||
Error ("A macro named '%m%p' is already defined", &CurTok.SVal);
|
Error ("A macro named `%m%p' is already defined", &CurTok.SVal);
|
||||||
PNotification (&Existing->DefPos,
|
PNotification (&Existing->DefPos,
|
||||||
"Previous definition of macro '%s' was here",
|
"Previous definition of macro `%s' was here",
|
||||||
SB_GetConstBuf (&Existing->Name));
|
SB_GetConstBuf (&Existing->Name));
|
||||||
/* Skip tokens until we reach the final .endmacro */
|
/* Skip tokens until we reach the final .endmacro */
|
||||||
MacSkipDef (Style, &StartPos);
|
MacSkipDef (Style, &StartPos);
|
||||||
@@ -478,7 +479,7 @@ void MacDef (unsigned Style)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
|
if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
|
||||||
Error ("Duplicate macro parameter '%m%p'", &CurTok.SVal);
|
Error ("Duplicate macro parameter `%m%p'", &CurTok.SVal);
|
||||||
M->HasError = 1;
|
M->HasError = 1;
|
||||||
}
|
}
|
||||||
if (List->Next == 0) {
|
if (List->Next == 0) {
|
||||||
@@ -529,7 +530,7 @@ void MacDef (unsigned Style)
|
|||||||
}
|
}
|
||||||
/* May not have end of file in a macro definition */
|
/* May not have end of file in a macro definition */
|
||||||
if (CurTok.Tok == TOK_EOF) {
|
if (CurTok.Tok == TOK_EOF) {
|
||||||
Error ("Missing '.ENDMACRO' for definition of macro '%s'",
|
Error ("Missing `.ENDMACRO' for definition of macro `%s'",
|
||||||
SB_GetConstBuf (&M->Name));
|
SB_GetConstBuf (&M->Name));
|
||||||
PNotification (&StartPos, "Macro definition started here");
|
PNotification (&StartPos, "Macro definition started here");
|
||||||
M->HasError = 1;
|
M->HasError = 1;
|
||||||
@@ -645,11 +646,11 @@ void MacUndef (const StrBuf* Name, unsigned char Style)
|
|||||||
|
|
||||||
/* Don't let the user kid with us */
|
/* Don't let the user kid with us */
|
||||||
if (M == 0 || M->Style != Style) {
|
if (M == 0 || M->Style != Style) {
|
||||||
Error ("No such macro: %m%p", Name);
|
Error ("No such macro: `%m%p'", Name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (M->Expansions > 0) {
|
if (M->Expansions > 0) {
|
||||||
Error ("Cannot delete macro '%s' which is currently expanded",
|
Error ("Cannot delete macro `%s' which is currently expanded",
|
||||||
SB_GetConstBuf (&M->Name));
|
SB_GetConstBuf (&M->Name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -837,10 +838,10 @@ static void StartExpClassic (MacExp* E)
|
|||||||
|
|
||||||
/* Check for maximum parameter count */
|
/* Check for maximum parameter count */
|
||||||
if (E->ParamCount >= E->M->ParamCount) {
|
if (E->ParamCount >= E->M->ParamCount) {
|
||||||
ErrorSkip ("Too many parameters for macro '%s'",
|
ErrorSkip ("Too many parameters for macro `%s'",
|
||||||
SB_GetConstBuf (&E->M->Name));
|
SB_GetConstBuf (&E->M->Name));
|
||||||
PNotification (&E->M->DefPos,
|
PNotification (&E->M->DefPos,
|
||||||
"See definition of macro '%s' which was here",
|
"See definition of macro `%s' which was here",
|
||||||
SB_GetConstBuf (&E->M->Name));
|
SB_GetConstBuf (&E->M->Name));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -966,7 +967,7 @@ static void StartExpDefine (MacExp* E)
|
|||||||
|
|
||||||
/* Check for a comma */
|
/* Check for a comma */
|
||||||
if (Count > 0) {
|
if (Count > 0) {
|
||||||
if (Expect (TOK_COMMA, "Expected ','")) {
|
if (Expect (TOK_COMMA, "Expected `,'")) {
|
||||||
NextTok ();
|
NextTok ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1000,18 +1001,18 @@ void MacExpandStart (Macro* M)
|
|||||||
|
|
||||||
/* We cannot expand a macro with errors */
|
/* We cannot expand a macro with errors */
|
||||||
if (M->HasError) {
|
if (M->HasError) {
|
||||||
PError (&Pos, "Macro '%s' contains errors and cannot be expanded",
|
PError (&Pos, "Macro `%s' contains errors and cannot be expanded",
|
||||||
SB_GetConstBuf (&M->Name));
|
SB_GetConstBuf (&M->Name));
|
||||||
PNotification (&M->DefPos, "Definition of macro '%s' was here",
|
PNotification (&M->DefPos, "Definition of macro `%s' was here",
|
||||||
SB_GetConstBuf (&M->Name));
|
SB_GetConstBuf (&M->Name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We cannot expand an incomplete macro */
|
/* We cannot expand an incomplete macro */
|
||||||
if (M->Incomplete) {
|
if (M->Incomplete) {
|
||||||
PError (&Pos, "Macro '%s' is incomplete and cannot be expanded",
|
PError (&Pos, "Macro `%s' is incomplete and cannot be expanded",
|
||||||
SB_GetConstBuf (&M->Name));
|
SB_GetConstBuf (&M->Name));
|
||||||
PNotification (&M->DefPos, "Definition of macro '%s' was here",
|
PNotification (&M->DefPos, "Definition of macro `%s' was here",
|
||||||
SB_GetConstBuf (&M->Name));
|
SB_GetConstBuf (&M->Name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1020,7 +1021,7 @@ void MacExpandStart (Macro* M)
|
|||||||
** to force an endless loop and assembler crash.
|
** to force an endless loop and assembler crash.
|
||||||
*/
|
*/
|
||||||
if (MacExpansions >= MAX_MACEXPANSIONS) {
|
if (MacExpansions >= MAX_MACEXPANSIONS) {
|
||||||
PError (&Pos, "Too many nested macro expansions for macro '%s'",
|
PError (&Pos, "Too many nested macro expansions for macro `%s'",
|
||||||
SB_GetConstBuf (&M->Name));
|
SB_GetConstBuf (&M->Name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
#include "addrsize.h"
|
#include "addrsize.h"
|
||||||
#include "chartype.h"
|
#include "chartype.h"
|
||||||
#include "cmdline.h"
|
#include "cmdline.h"
|
||||||
|
#include "consprop.h"
|
||||||
#include "debugflag.h"
|
#include "debugflag.h"
|
||||||
#include "mmodel.h"
|
#include "mmodel.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
@@ -56,6 +57,7 @@
|
|||||||
#include "asserts.h"
|
#include "asserts.h"
|
||||||
#include "dbginfo.h"
|
#include "dbginfo.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "feature.h"
|
#include "feature.h"
|
||||||
#include "filetab.h"
|
#include "filetab.h"
|
||||||
@@ -111,6 +113,7 @@ static void Usage (void)
|
|||||||
"Long options:\n"
|
"Long options:\n"
|
||||||
" --auto-import\t\t\tMark unresolved symbols as import\n"
|
" --auto-import\t\t\tMark unresolved symbols as import\n"
|
||||||
" --bin-include-dir dir\t\tSet a search path for binary includes\n"
|
" --bin-include-dir dir\t\tSet a search path for binary includes\n"
|
||||||
|
" --color [on|auto|off]\t\tColor diagnostics (default: auto)\n"
|
||||||
" --cpu type\t\t\tSet cpu type\n"
|
" --cpu type\t\t\tSet cpu type\n"
|
||||||
" --create-dep name\t\tCreate a make dependency file\n"
|
" --create-dep name\t\tCreate a make dependency file\n"
|
||||||
" --create-full-dep name\tCreate a full make dependency file\n"
|
" --create-full-dep name\tCreate a full make dependency file\n"
|
||||||
@@ -124,12 +127,14 @@ static void Usage (void)
|
|||||||
" --listing name\t\tCreate a listing file if assembly was ok\n"
|
" --listing name\t\tCreate a listing file if assembly was ok\n"
|
||||||
" --list-bytes n\t\tMaximum number of bytes per listing line\n"
|
" --list-bytes n\t\tMaximum number of bytes per listing line\n"
|
||||||
" --memory-model model\t\tSet the memory model\n"
|
" --memory-model model\t\tSet the memory model\n"
|
||||||
|
" --no-utf8\t\t\tDisable use of UTF-8 in diagnostics\n"
|
||||||
" --pagelength n\t\tSet the page length for the listing\n"
|
" --pagelength n\t\tSet the page length for the listing\n"
|
||||||
" --relax-checks\t\tRelax some checks (see docs)\n"
|
" --relax-checks\t\tRelax some checks (see docs)\n"
|
||||||
" --smart\t\t\tEnable smart mode\n"
|
" --smart\t\t\tEnable smart mode\n"
|
||||||
" --target sys\t\t\tSet the target system\n"
|
" --target sys\t\t\tSet the target system\n"
|
||||||
" --verbose\t\t\tIncrease verbosity\n"
|
" --verbose\t\t\tIncrease verbosity\n"
|
||||||
" --version\t\t\tPrint the assembler version\n",
|
" --version\t\t\tPrint the assembler version\n"
|
||||||
|
" --warnings-as-errors\t\tTreat warnings as errors\n",
|
||||||
ProgName);
|
ProgName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,6 +497,22 @@ static void OptBinIncludeDir (const char* Opt attribute ((unused)), const char*
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void OptColor(const char* Opt, const char* Arg)
|
||||||
|
/* Handle the --color option */
|
||||||
|
{
|
||||||
|
if (strcmp (Arg, "off") == 0 || strcmp (Arg, "false") == 0) {
|
||||||
|
CP_SetColorMode (CM_OFF);
|
||||||
|
} else if (strcmp (Arg, "auto") == 0) {
|
||||||
|
CP_SetColorMode (CM_AUTO);
|
||||||
|
} else if (strcmp (Arg, "on") == 0 || strcmp (Arg, "true") == 0) {
|
||||||
|
CP_SetColorMode (CM_ON);
|
||||||
|
} else {
|
||||||
|
AbEnd ("Invalid argument to %s: %s", Opt, Arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void OptCPU (const char* Opt attribute ((unused)), const char* Arg)
|
static void OptCPU (const char* Opt attribute ((unused)), const char* Arg)
|
||||||
/* Handle the --cpu option */
|
/* Handle the --cpu option */
|
||||||
{
|
{
|
||||||
@@ -622,7 +643,7 @@ static void OptListing (const char* Opt, const char* Arg)
|
|||||||
** the filename is empty or begins with the option char.
|
** the filename is empty or begins with the option char.
|
||||||
*/
|
*/
|
||||||
if (Arg == 0 || *Arg == '\0' || *Arg == '-') {
|
if (Arg == 0 || *Arg == '\0' || *Arg == '-') {
|
||||||
Fatal ("The meaning of '%s' has changed. It does now "
|
Fatal ("The meaning of `%s' has changed. It does now "
|
||||||
"expect a file name as argument.", Opt);
|
"expect a file name as argument.", Opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,6 +677,15 @@ static void OptMemoryModel (const char* Opt, const char* Arg)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void OptNoUtf8 (const char* Opt attribute ((unused)),
|
||||||
|
const char* Arg attribute ((unused)))
|
||||||
|
/* Handle the --no-utf8 option */
|
||||||
|
{
|
||||||
|
CP_DisableUTF8 ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void OptPageLength (const char* Opt attribute ((unused)), const char* Arg)
|
static void OptPageLength (const char* Opt attribute ((unused)), const char* Arg)
|
||||||
/* Handle the --pagelength option */
|
/* Handle the --pagelength option */
|
||||||
{
|
{
|
||||||
@@ -771,7 +801,7 @@ static void OneLine (void)
|
|||||||
if (CurTok.Tok == TOK_COLON) {
|
if (CurTok.Tok == TOK_COLON) {
|
||||||
NextTok ();
|
NextTok ();
|
||||||
} else if (CurTok.WS || !NoColonLabels) {
|
} else if (CurTok.WS || !NoColonLabels) {
|
||||||
Error ("':' expected");
|
Error ("`:' expected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -857,7 +887,7 @@ static void OneLine (void)
|
|||||||
*/
|
*/
|
||||||
if (CurTok.Tok != TOK_COLON) {
|
if (CurTok.Tok != TOK_COLON) {
|
||||||
if (HadWS || !NoColonLabels) {
|
if (HadWS || !NoColonLabels) {
|
||||||
ErrorExpect ("Expected ':' after identifier to form a label");
|
ErrorExpect ("Expected `:' after identifier to form a label");
|
||||||
SkipUntilSep ();
|
SkipUntilSep ();
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
@@ -902,7 +932,7 @@ static void OneLine (void)
|
|||||||
HandleInstruction (Instr);
|
HandleInstruction (Instr);
|
||||||
} else if (PCAssignment && (CurTok.Tok == TOK_STAR || CurTok.Tok == TOK_PC)) {
|
} else if (PCAssignment && (CurTok.Tok == TOK_STAR || CurTok.Tok == TOK_PC)) {
|
||||||
NextTok ();
|
NextTok ();
|
||||||
if (!ExpectSkip (TOK_EQ, "Expected '='")) {
|
if (!ExpectSkip (TOK_EQ, "Expected `='")) {
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
/* Skip the equal sign */
|
/* Skip the equal sign */
|
||||||
@@ -1013,6 +1043,7 @@ int main (int argc, char* argv [])
|
|||||||
static const LongOpt OptTab[] = {
|
static const LongOpt OptTab[] = {
|
||||||
{ "--auto-import", 0, OptAutoImport },
|
{ "--auto-import", 0, OptAutoImport },
|
||||||
{ "--bin-include-dir", 1, OptBinIncludeDir },
|
{ "--bin-include-dir", 1, OptBinIncludeDir },
|
||||||
|
{ "--color", 1, OptColor },
|
||||||
{ "--cpu", 1, OptCPU },
|
{ "--cpu", 1, OptCPU },
|
||||||
{ "--create-dep", 1, OptCreateDep },
|
{ "--create-dep", 1, OptCreateDep },
|
||||||
{ "--create-full-dep", 1, OptCreateFullDep },
|
{ "--create-full-dep", 1, OptCreateFullDep },
|
||||||
@@ -1026,6 +1057,7 @@ int main (int argc, char* argv [])
|
|||||||
{ "--list-bytes", 1, OptListBytes },
|
{ "--list-bytes", 1, OptListBytes },
|
||||||
{ "--listing", 1, OptListing },
|
{ "--listing", 1, OptListing },
|
||||||
{ "--memory-model", 1, OptMemoryModel },
|
{ "--memory-model", 1, OptMemoryModel },
|
||||||
|
{ "--no-utf8", 0, OptNoUtf8 },
|
||||||
{ "--pagelength", 1, OptPageLength },
|
{ "--pagelength", 1, OptPageLength },
|
||||||
{ "--relax-checks", 0, OptRelaxChecks },
|
{ "--relax-checks", 0, OptRelaxChecks },
|
||||||
{ "--smart", 0, OptSmart },
|
{ "--smart", 0, OptSmart },
|
||||||
@@ -1040,6 +1072,9 @@ int main (int argc, char* argv [])
|
|||||||
|
|
||||||
unsigned I;
|
unsigned I;
|
||||||
|
|
||||||
|
/* Initialize console output */
|
||||||
|
CP_Init ();
|
||||||
|
|
||||||
/* Initialize the cmdline module */
|
/* Initialize the cmdline module */
|
||||||
InitCmdLine (&argc, &argv, "ca65");
|
InitCmdLine (&argc, &argv, "ca65");
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "condasm.h"
|
#include "condasm.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
@@ -179,7 +180,7 @@ static void FuncConcat (void)
|
|||||||
** by the string token just created.
|
** by the string token just created.
|
||||||
*/
|
*/
|
||||||
if (CurTok.Tok != TOK_RPAREN) {
|
if (CurTok.Tok != TOK_RPAREN) {
|
||||||
Error ("')' expected");
|
Error ("`)' expected");
|
||||||
} else {
|
} else {
|
||||||
CurTok.Tok = TOK_STRCON;
|
CurTok.Tok = TOK_STRCON;
|
||||||
SB_Copy (&CurTok.SVal, &Buf);
|
SB_Copy (&CurTok.SVal, &Buf);
|
||||||
@@ -253,7 +254,7 @@ static void FuncIdent (void)
|
|||||||
SB_Copy (&Buf, &CurTok.SVal);
|
SB_Copy (&Buf, &CurTok.SVal);
|
||||||
NextTok ();
|
NextTok ();
|
||||||
if (CurTok.Tok != TOK_RPAREN) {
|
if (CurTok.Tok != TOK_RPAREN) {
|
||||||
Error ("')' expected");
|
Error ("`)' expected");
|
||||||
} else {
|
} else {
|
||||||
CurTok.Tok = Id;
|
CurTok.Tok = Id;
|
||||||
SB_Copy (&CurTok.SVal, &Buf);
|
SB_Copy (&CurTok.SVal, &Buf);
|
||||||
@@ -600,7 +601,7 @@ static void FuncSPrintF (void)
|
|||||||
** by the string token just created.
|
** by the string token just created.
|
||||||
*/
|
*/
|
||||||
if (CurTok.Tok != TOK_RPAREN) {
|
if (CurTok.Tok != TOK_RPAREN) {
|
||||||
Error ("')' expected");
|
Error ("`)' expected");
|
||||||
} else {
|
} else {
|
||||||
CurTok.Tok = TOK_STRCON;
|
CurTok.Tok = TOK_STRCON;
|
||||||
SB_Copy (&CurTok.SVal, &R);
|
SB_Copy (&CurTok.SVal, &R);
|
||||||
@@ -660,7 +661,7 @@ static void FuncString (void)
|
|||||||
** by the string token just created.
|
** by the string token just created.
|
||||||
*/
|
*/
|
||||||
if (CurTok.Tok != TOK_RPAREN) {
|
if (CurTok.Tok != TOK_RPAREN) {
|
||||||
Error ("')' expected");
|
Error ("`)' expected");
|
||||||
} else {
|
} else {
|
||||||
CurTok.Tok = TOK_STRCON;
|
CurTok.Tok = TOK_STRCON;
|
||||||
SB_Copy (&CurTok.SVal, &Buf);
|
SB_Copy (&CurTok.SVal, &Buf);
|
||||||
@@ -725,59 +726,6 @@ void NextTok (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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 then 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
|
|
||||||
* then 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 then 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)
|
int Consume (token_t Expected, const char* ErrMsg)
|
||||||
/* Consume Token, print an error if we don't find it. Return true if the token
|
/* Consume Token, print an error if we don't find it. Return true if the token
|
||||||
** was found and false otherwise.
|
** was found and false otherwise.
|
||||||
@@ -816,7 +764,7 @@ int ConsumeLParen (void)
|
|||||||
** otherwise.
|
** otherwise.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
return Consume (TOK_LPAREN, "Expected '('");
|
return Consume (TOK_LPAREN, "Expected `('");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -826,7 +774,7 @@ int ConsumeRParen (void)
|
|||||||
** otherwise.
|
** otherwise.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
return Consume (TOK_RPAREN, "Expected ')'");
|
return Consume (TOK_RPAREN, "Expected `)'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -836,7 +784,7 @@ int ConsumeComma (void)
|
|||||||
** otherwise.
|
** otherwise.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
return Consume (TOK_COMMA, "Expected ','");
|
return Consume (TOK_COMMA, "Expected `,'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -851,26 +799,6 @@ void SkipUntilSep (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
/* Try to be helpful by giving information about the token that was
|
|
||||||
* unexpected.
|
|
||||||
*/
|
|
||||||
ErrorExpect ("Expected 'end-of-line'");
|
|
||||||
SkipUntilSep ();
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void EnterRawTokenMode (void)
|
void EnterRawTokenMode (void)
|
||||||
/* Enter raw token mode. In raw mode, token handling functions are not
|
/* Enter raw token mode. In raw mode, token handling functions are not
|
||||||
** executed, but the function tokens are passed untouched to the upper
|
** executed, but the function tokens are passed untouched to the upper
|
||||||
|
|||||||
@@ -51,30 +51,6 @@
|
|||||||
void NextTok (void);
|
void NextTok (void);
|
||||||
/* Get next token and handle token level functions */
|
/* Get next token and handle token level functions */
|
||||||
|
|
||||||
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 then be
|
|
||||||
* "xyz expected but found zyx".
|
|
||||||
*/
|
|
||||||
|
|
||||||
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
|
|
||||||
* then be "xyz expected but found zyx".
|
|
||||||
* Returns true if the token was found, otherwise false.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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 then be "xyz expected but found
|
|
||||||
* zyx".
|
|
||||||
* Returns true if the token was found, otherwise false.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int Consume (token_t Expected, const char* ErrMsg);
|
int Consume (token_t Expected, const char* ErrMsg);
|
||||||
/* Consume Token, print an error if we don't find it. Return true if the token
|
/* Consume Token, print an error if we don't find it. Return true if the token
|
||||||
** was found and false otherwise.
|
** was found and false otherwise.
|
||||||
@@ -103,12 +79,6 @@ int ConsumeComma (void);
|
|||||||
void SkipUntilSep (void);
|
void SkipUntilSep (void);
|
||||||
/* Skip tokens until we reach a line separator or end of file */
|
/* Skip tokens until we reach a line separator or end of file */
|
||||||
|
|
||||||
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);
|
void EnterRawTokenMode (void);
|
||||||
/* Enter raw token mode. In raw mode, token handling functions are not
|
/* Enter raw token mode. In raw mode, token handling functions are not
|
||||||
** executed, but the function tokens are passed untouched to the upper
|
** executed, but the function tokens are passed untouched to the upper
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ static void ObjWriteError (void)
|
|||||||
remove (OutFile);
|
remove (OutFile);
|
||||||
|
|
||||||
/* Now abort with a fatal error */
|
/* Now abort with a fatal error */
|
||||||
Fatal ("Cannot write to output file '%s': %s", OutFile, strerror (Error));
|
Fatal ("Cannot write to output file `%s': %s", OutFile, strerror (Error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ void ObjOpen (void)
|
|||||||
/* Create the output file */
|
/* Create the output file */
|
||||||
F = fopen (OutFile, "w+b");
|
F = fopen (OutFile, "w+b");
|
||||||
if (F == 0) {
|
if (F == 0) {
|
||||||
Fatal ("Cannot open output file '%s': %s", OutFile, strerror (errno));
|
Fatal ("Cannot open output file `%s': %s", OutFile, strerror (errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a dummy header */
|
/* Write a dummy header */
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
#include "dbginfo.h"
|
#include "dbginfo.h"
|
||||||
#include "enum.h"
|
#include "enum.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "feature.h"
|
#include "feature.h"
|
||||||
#include "filetab.h"
|
#include "filetab.h"
|
||||||
@@ -1038,13 +1039,13 @@ static void DoFeature (void)
|
|||||||
Feature = FindFeature (&CurTok.SVal);
|
Feature = FindFeature (&CurTok.SVal);
|
||||||
if (Feature == FEAT_UNKNOWN) {
|
if (Feature == FEAT_UNKNOWN) {
|
||||||
/* Not found */
|
/* Not found */
|
||||||
ErrorSkip ("Invalid feature: '%m%p'", &CurTok.SVal);
|
ErrorSkip ("Invalid feature: `%m%p'", &CurTok.SVal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Feature == FEAT_ADDRSIZE) {
|
if (Feature == FEAT_ADDRSIZE) {
|
||||||
Warning (1, "Deprecated feature: '.feature addrsize'. "
|
Warning (1, "Deprecated feature `addrsize'");
|
||||||
"Pseudo function .addrsize is always available.");
|
Notification ("Pseudo function `.addrsize' is always available");
|
||||||
}
|
}
|
||||||
|
|
||||||
NextTok ();
|
NextTok ();
|
||||||
@@ -1270,7 +1271,7 @@ static void DoIncBin (void)
|
|||||||
char* PathName = SearchFile (BinSearchPath, SB_GetConstBuf (&Name));
|
char* PathName = SearchFile (BinSearchPath, SB_GetConstBuf (&Name));
|
||||||
if (PathName == 0 || (F = fopen (PathName, "rb")) == 0) {
|
if (PathName == 0 || (F = fopen (PathName, "rb")) == 0) {
|
||||||
/* Not found or cannot open, print an error and bail out */
|
/* Not found or cannot open, print an error and bail out */
|
||||||
ErrorSkip ("Cannot open include file '%m%p': %s", &Name, strerror (errno));
|
ErrorSkip ("Cannot open include file `%m%p': %s", &Name, strerror (errno));
|
||||||
xfree (PathName);
|
xfree (PathName);
|
||||||
goto ExitPoint;
|
goto ExitPoint;
|
||||||
}
|
}
|
||||||
@@ -1296,7 +1297,7 @@ static void DoIncBin (void)
|
|||||||
*/
|
*/
|
||||||
SB_Terminate (&Name);
|
SB_Terminate (&Name);
|
||||||
if (FileStat (SB_GetConstBuf (&Name), &StatBuf) != 0) {
|
if (FileStat (SB_GetConstBuf (&Name), &StatBuf) != 0) {
|
||||||
Fatal ("Cannot stat input file '%m%p': %s", &Name, strerror (errno));
|
Fatal ("Cannot stat input file `%m%p': %s", &Name, strerror (errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the file to the input file table */
|
/* Add the file to the input file table */
|
||||||
@@ -1336,7 +1337,7 @@ static void DoIncBin (void)
|
|||||||
size_t BytesRead = fread (Buf, 1, BytesToRead, F);
|
size_t BytesRead = fread (Buf, 1, BytesToRead, F);
|
||||||
if (BytesToRead != BytesRead) {
|
if (BytesToRead != BytesRead) {
|
||||||
/* Some sort of error */
|
/* Some sort of error */
|
||||||
ErrorSkip ("Cannot read from include file '%m%p': %s",
|
ErrorSkip ("Cannot read from include file `%m%p': %s",
|
||||||
&Name, strerror (errno));
|
&Name, strerror (errno));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2019,7 +2020,7 @@ static void DoUnDef (void)
|
|||||||
static void DoUnexpected (void)
|
static void DoUnexpected (void)
|
||||||
/* Got an unexpected keyword */
|
/* Got an unexpected keyword */
|
||||||
{
|
{
|
||||||
Error ("Unexpected '%m%p'", &Keyword);
|
Error ("Unexpected `%m%p'", &Keyword);
|
||||||
SkipUntilSep ();
|
SkipUntilSep ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "nexttok.h"
|
#include "nexttok.h"
|
||||||
#include "toklist.h"
|
#include "toklist.h"
|
||||||
@@ -67,8 +68,8 @@ static TokList* CollectRepeatTokens (const FilePos* StartPos)
|
|||||||
|
|
||||||
/* Check for end of input */
|
/* Check for end of input */
|
||||||
if (CurTok.Tok == TOK_EOF) {
|
if (CurTok.Tok == TOK_EOF) {
|
||||||
ErrorExpect ("Expected '.ENDREPEAT'");
|
ErrorExpect ("Expected `.ENDREPEAT'");
|
||||||
PNotification (StartPos, "For this '.REPEAT' command");
|
PNotification (StartPos, "For this `.REPEAT' command");
|
||||||
FreeTokList (List);
|
FreeTokList (List);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "condasm.h"
|
#include "condasm.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "filetab.h"
|
#include "filetab.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "incpath.h"
|
#include "incpath.h"
|
||||||
@@ -545,7 +546,7 @@ int NewInputFile (const char* Name)
|
|||||||
/* Main file */
|
/* Main file */
|
||||||
F = fopen (Name, "r");
|
F = fopen (Name, "r");
|
||||||
if (F == 0) {
|
if (F == 0) {
|
||||||
Fatal ("Cannot open input file '%s': %s", Name, strerror (errno));
|
Fatal ("Cannot open input file `%s': %s", Name, strerror (errno));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* We are on include level. Search for the file in the include
|
/* We are on include level. Search for the file in the include
|
||||||
@@ -554,7 +555,7 @@ int NewInputFile (const char* Name)
|
|||||||
PathName = SearchFile (IncSearchPath, Name);
|
PathName = SearchFile (IncSearchPath, Name);
|
||||||
if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
|
if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
|
||||||
/* Not found or cannot open, print an error and bail out */
|
/* Not found or cannot open, print an error and bail out */
|
||||||
Error ("Cannot open include file '%s': %s", Name, strerror (errno));
|
Error ("Cannot open include file `%s': %s", Name, strerror (errno));
|
||||||
goto ExitPoint;
|
goto ExitPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,7 +572,7 @@ int NewInputFile (const char* Name)
|
|||||||
** here.
|
** here.
|
||||||
*/
|
*/
|
||||||
if (FileStat (Name, &Buf) != 0) {
|
if (FileStat (Name, &Buf) != 0) {
|
||||||
Fatal ("Cannot stat input file '%s': %s", Name, strerror (errno));
|
Fatal ("Cannot stat input file `%s': %s", Name, strerror (errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the file to the input file table and remember the index */
|
/* Add the file to the input file table and remember the index */
|
||||||
@@ -1196,7 +1197,7 @@ Again:
|
|||||||
/* Not found */
|
/* Not found */
|
||||||
if (!LeadingDotInIdents) {
|
if (!LeadingDotInIdents) {
|
||||||
/* Invalid pseudo instruction */
|
/* Invalid pseudo instruction */
|
||||||
Error ("'%m%p' is not a recognized control command", &CurTok.SVal);
|
Error ("`%m%p' is not a recognized control command", &CurTok.SVal);
|
||||||
goto Again;
|
goto Again;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1686,14 +1687,14 @@ unsigned char ParseAddrSize (void)
|
|||||||
|
|
||||||
/* Check for an identifier */
|
/* Check for an identifier */
|
||||||
if (CurTok.Tok != TOK_IDENT) {
|
if (CurTok.Tok != TOK_IDENT) {
|
||||||
Error ("Address size specifier expected");
|
ErrorExpect ("Expected an address size specifier");
|
||||||
return ADDR_SIZE_DEFAULT;
|
return ADDR_SIZE_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert the attribute */
|
/* Convert the attribute */
|
||||||
AddrSize = AddrSizeFromStr (SB_GetConstBuf (&CurTok.SVal));
|
AddrSize = AddrSizeFromStr (SB_GetConstBuf (&CurTok.SVal));
|
||||||
if (AddrSize == ADDR_SIZE_INVALID) {
|
if (AddrSize == ADDR_SIZE_INVALID) {
|
||||||
Error ("Address size specifier expected");
|
ErrorExpect ("Expected an address size specifier");
|
||||||
AddrSize = ADDR_SIZE_DEFAULT;
|
AddrSize = ADDR_SIZE_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ static Segment* NewSegment (const char* Name, unsigned char AddrSize)
|
|||||||
|
|
||||||
/* Check the segment name for invalid names */
|
/* Check the segment name for invalid names */
|
||||||
if (!ValidSegName (Name)) {
|
if (!ValidSegName (Name)) {
|
||||||
Error ("Illegal segment name: '%s'", Name);
|
Error ("Illegal segment name: `%s'", Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new segment and return it */
|
/* Create a new segment and return it */
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "condasm.h"
|
#include "condasm.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "nexttok.h"
|
#include "nexttok.h"
|
||||||
@@ -287,9 +288,9 @@ static long DoStructInternal (long Offs, unsigned Type)
|
|||||||
|
|
||||||
/* End of struct/union definition */
|
/* End of struct/union definition */
|
||||||
if (Type == STRUCT) {
|
if (Type == STRUCT) {
|
||||||
Consume (TOK_ENDSTRUCT, "Expected '.ENDSTRUCT'");
|
Consume (TOK_ENDSTRUCT, "Expected `.ENDSTRUCT'");
|
||||||
} else {
|
} else {
|
||||||
Consume (TOK_ENDUNION, "Expected '.ENDUNION'");
|
Consume (TOK_ENDUNION, "Expected `.ENDUNION'");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the size of the struct */
|
/* Return the size of the struct */
|
||||||
|
|||||||
@@ -593,7 +593,7 @@ static void StudySymbol (ExprNode* Expr, ExprDesc* D)
|
|||||||
|
|
||||||
if (SymHasUserMark (Sym)) {
|
if (SymHasUserMark (Sym)) {
|
||||||
LIError (&Sym->DefLines,
|
LIError (&Sym->DefLines,
|
||||||
"Circular reference in definition of symbol '%m%p'",
|
"Circular reference in definition of symbol `%m%p'",
|
||||||
GetSymName (Sym));
|
GetSymName (Sym));
|
||||||
ED_SetError (D);
|
ED_SetError (D);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
/* ca65 */
|
/* ca65 */
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "expect.h"
|
||||||
#include "nexttok.h"
|
#include "nexttok.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
@@ -95,7 +96,7 @@ SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
|
|||||||
if (Scope == 0) {
|
if (Scope == 0) {
|
||||||
/* Scope not found */
|
/* Scope not found */
|
||||||
SB_Terminate (FullName);
|
SB_Terminate (FullName);
|
||||||
Error ("No such scope: '%m%p'", FullName);
|
Error ("No such scope: `%m%p'", FullName);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +139,7 @@ SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
|
|||||||
Scope = SymFindScope (Scope, Name, SYM_FIND_EXISTING);
|
Scope = SymFindScope (Scope, Name, SYM_FIND_EXISTING);
|
||||||
if (Scope == 0) {
|
if (Scope == 0) {
|
||||||
/* Scope not found */
|
/* Scope not found */
|
||||||
Error ("No such scope: '%m%p'", FullName);
|
Error ("No such scope: `%m%p'", FullName);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags
|
|||||||
|
|
||||||
if (S->Flags & SF_IMPORT) {
|
if (S->Flags & SF_IMPORT) {
|
||||||
/* Defined symbol is marked as imported external symbol */
|
/* Defined symbol is marked as imported external symbol */
|
||||||
Error ("Symbol '%m%p' is already an import", GetSymName (S));
|
Error ("Symbol `%m%p' is already an import", GetSymName (S));
|
||||||
if (CollCount (&S->DefLines) > 0) {
|
if (CollCount (&S->DefLines) > 0) {
|
||||||
PNotification (GetSourcePos (CollAt(&S->DefLines, 0)),
|
PNotification (GetSourcePos (CollAt(&S->DefLines, 0)),
|
||||||
"The symbol was previously imported here");
|
"The symbol was previously imported here");
|
||||||
@@ -224,13 +224,13 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags
|
|||||||
}
|
}
|
||||||
if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
|
if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
|
||||||
/* Variable symbols cannot be exports or globals */
|
/* Variable symbols cannot be exports or globals */
|
||||||
Error ("Var symbol '%m%p' cannot be an export or global symbol", GetSymName (S));
|
Error ("Var symbol `%m%p' cannot be an export or global symbol", GetSymName (S));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (S->Flags & SF_DEFINED) {
|
if (S->Flags & SF_DEFINED) {
|
||||||
/* Multiple definition. In case of a variable, this is legal. */
|
/* Multiple definition. In case of a variable, this is legal. */
|
||||||
if ((S->Flags & SF_VAR) == 0) {
|
if ((S->Flags & SF_VAR) == 0) {
|
||||||
Error ("Symbol '%m%p' is already defined", GetSymName (S));
|
Error ("Symbol `%m%p' is already defined", GetSymName (S));
|
||||||
if (CollCount (&S->DefLines) > 0) {
|
if (CollCount (&S->DefLines) > 0) {
|
||||||
PNotification (GetSourcePos (CollAt(&S->DefLines, 0)),
|
PNotification (GetSourcePos (CollAt(&S->DefLines, 0)),
|
||||||
"The symbol was previously defined here");
|
"The symbol was previously defined here");
|
||||||
@@ -240,7 +240,7 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags
|
|||||||
} else {
|
} else {
|
||||||
/* Redefinition must also be a variable symbol */
|
/* Redefinition must also be a variable symbol */
|
||||||
if ((Flags & SF_VAR) == 0) {
|
if ((Flags & SF_VAR) == 0) {
|
||||||
Error ("Symbol '%m%p' is already different kind", GetSymName (S));
|
Error ("Symbol `%m%p' is already different kind", GetSymName (S));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Delete the current symbol expression, since it will get
|
/* Delete the current symbol expression, since it will get
|
||||||
@@ -296,7 +296,7 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags
|
|||||||
S->ExportSize = S->AddrSize;
|
S->ExportSize = S->AddrSize;
|
||||||
} else if (S->AddrSize > S->ExportSize) {
|
} else if (S->AddrSize > S->ExportSize) {
|
||||||
/* We're exporting a symbol smaller than it actually is */
|
/* We're exporting a symbol smaller than it actually is */
|
||||||
Warning (1, "Symbol '%m%p' is %s but exported %s",
|
Warning (1, "Symbol `%m%p' is %s but exported %s",
|
||||||
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
||||||
AddrSizeToStr (S->ExportSize));
|
AddrSizeToStr (S->ExportSize));
|
||||||
}
|
}
|
||||||
@@ -328,13 +328,13 @@ void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
/* Mark the given symbol as an imported symbol */
|
/* Mark the given symbol as an imported symbol */
|
||||||
{
|
{
|
||||||
if (S->Flags & SF_DEFINED) {
|
if (S->Flags & SF_DEFINED) {
|
||||||
Error ("Symbol '%m%p' is already defined", GetSymName (S));
|
Error ("Symbol `%m%p' is already defined", GetSymName (S));
|
||||||
S->Flags |= SF_MULTDEF;
|
S->Flags |= SF_MULTDEF;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (S->Flags & SF_EXPORT) {
|
if (S->Flags & SF_EXPORT) {
|
||||||
/* The symbol is already marked as exported symbol */
|
/* The symbol is already marked as exported symbol */
|
||||||
Error ("Cannot import exported symbol '%m%p'", GetSymName (S));
|
Error ("Cannot import exported symbol `%m%p'", GetSymName (S));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,16 +350,16 @@ void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
*/
|
*/
|
||||||
if (S->Flags & SF_IMPORT) {
|
if (S->Flags & SF_IMPORT) {
|
||||||
if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
|
if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
|
||||||
Error ("Redeclaration mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
if (AddrSize != S->AddrSize) {
|
if (AddrSize != S->AddrSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (S->Flags & SF_GLOBAL) {
|
if (S->Flags & SF_GLOBAL) {
|
||||||
S->Flags &= ~SF_GLOBAL;
|
S->Flags &= ~SF_GLOBAL;
|
||||||
if (AddrSize != S->AddrSize) {
|
if (AddrSize != S->AddrSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,12 +382,12 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
/* Check if it's ok to export the symbol */
|
/* Check if it's ok to export the symbol */
|
||||||
if (S->Flags & SF_IMPORT) {
|
if (S->Flags & SF_IMPORT) {
|
||||||
/* The symbol is already marked as imported external symbol */
|
/* The symbol is already marked as imported external symbol */
|
||||||
Error ("Symbol '%m%p' is already an import", GetSymName (S));
|
Error ("Symbol `%m%p' is already an import", GetSymName (S));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (S->Flags & SF_VAR) {
|
if (S->Flags & SF_VAR) {
|
||||||
/* Variable symbols cannot be exported */
|
/* Variable symbols cannot be exported */
|
||||||
Error ("Var symbol '%m%p' cannot be exported", GetSymName (S));
|
Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +396,7 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
*/
|
*/
|
||||||
if (S->Flags & SF_GLOBAL) {
|
if (S->Flags & SF_GLOBAL) {
|
||||||
if (AddrSize != S->ExportSize) {
|
if (AddrSize != S->ExportSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
S->Flags &= ~SF_GLOBAL;
|
S->Flags &= ~SF_GLOBAL;
|
||||||
|
|
||||||
@@ -411,7 +411,7 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
*/
|
*/
|
||||||
if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
|
if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
|
||||||
if (S->ExportSize != AddrSize) {
|
if (S->ExportSize != AddrSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
S->ExportSize = AddrSize;
|
S->ExportSize = AddrSize;
|
||||||
@@ -425,7 +425,7 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
S->ExportSize = S->AddrSize;
|
S->ExportSize = S->AddrSize;
|
||||||
} else if (S->AddrSize > S->ExportSize) {
|
} else if (S->AddrSize > S->ExportSize) {
|
||||||
/* We're exporting a symbol smaller than it actually is */
|
/* We're exporting a symbol smaller than it actually is */
|
||||||
Warning (1, "Symbol '%m%p' is %s but exported %s",
|
Warning (1, "Symbol `%m%p' is %s but exported %s",
|
||||||
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
||||||
AddrSizeToStr (S->ExportSize));
|
AddrSizeToStr (S->ExportSize));
|
||||||
}
|
}
|
||||||
@@ -447,7 +447,7 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
{
|
{
|
||||||
if (S->Flags & SF_VAR) {
|
if (S->Flags & SF_VAR) {
|
||||||
/* Variable symbols cannot be exported or imported */
|
/* Variable symbols cannot be exported or imported */
|
||||||
Error ("Var symbol '%m%p' cannot be made global", GetSymName (S));
|
Error ("Var symbol `%m%p' cannot be made global", GetSymName (S));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,7 +460,7 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
AddrSize = GetCurrentSegAddrSize ();
|
AddrSize = GetCurrentSegAddrSize ();
|
||||||
}
|
}
|
||||||
if (AddrSize != S->AddrSize) {
|
if (AddrSize != S->AddrSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -472,12 +472,12 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
if ((S->Flags & SF_DEFINED) == 0) {
|
if ((S->Flags & SF_DEFINED) == 0) {
|
||||||
/* Symbol is undefined */
|
/* Symbol is undefined */
|
||||||
if (AddrSize != S->ExportSize) {
|
if (AddrSize != S->ExportSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
} else if (AddrSize != ADDR_SIZE_DEFAULT) {
|
} else if (AddrSize != ADDR_SIZE_DEFAULT) {
|
||||||
/* Symbol is defined and address size given */
|
/* Symbol is defined and address size given */
|
||||||
if (AddrSize != S->ExportSize) {
|
if (AddrSize != S->ExportSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -489,7 +489,7 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
*/
|
*/
|
||||||
if (S->Flags & SF_GLOBAL) {
|
if (S->Flags & SF_GLOBAL) {
|
||||||
if (AddrSize != S->ExportSize) {
|
if (AddrSize != S->ExportSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -507,7 +507,7 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||||||
S->ExportSize = S->AddrSize;
|
S->ExportSize = S->AddrSize;
|
||||||
} else if (S->AddrSize > S->ExportSize) {
|
} else if (S->AddrSize > S->ExportSize) {
|
||||||
/* We're exporting a symbol smaller than it actually is */
|
/* We're exporting a symbol smaller than it actually is */
|
||||||
Warning (1, "Symbol '%m%p' is %s but exported %s",
|
Warning (1, "Symbol `%m%p' is %s but exported %s",
|
||||||
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
||||||
AddrSizeToStr (S->ExportSize));
|
AddrSizeToStr (S->ExportSize));
|
||||||
}
|
}
|
||||||
@@ -550,12 +550,12 @@ void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Pri
|
|||||||
/* Check for errors */
|
/* Check for errors */
|
||||||
if (S->Flags & SF_IMPORT) {
|
if (S->Flags & SF_IMPORT) {
|
||||||
/* The symbol is already marked as imported external symbol */
|
/* The symbol is already marked as imported external symbol */
|
||||||
Error ("Symbol '%m%p' is already an import", GetSymName (S));
|
Error ("Symbol `%m%p' is already an import", GetSymName (S));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (S->Flags & SF_VAR) {
|
if (S->Flags & SF_VAR) {
|
||||||
/* Variable symbols cannot be exported or imported */
|
/* Variable symbols cannot be exported or imported */
|
||||||
Error ("Var symbol '%m%p' cannot be exported", GetSymName (S));
|
Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,7 +567,7 @@ void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Pri
|
|||||||
/* Use the real size of the symbol */
|
/* Use the real size of the symbol */
|
||||||
AddrSize = S->AddrSize;
|
AddrSize = S->AddrSize;
|
||||||
} else if (S->AddrSize != AddrSize) {
|
} else if (S->AddrSize != AddrSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,7 +577,7 @@ void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Pri
|
|||||||
*/
|
*/
|
||||||
if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
|
if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
|
||||||
if (S->ExportSize != AddrSize) {
|
if (S->ExportSize != AddrSize) {
|
||||||
Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
S->Flags &= ~SF_GLOBAL;
|
S->Flags &= ~SF_GLOBAL;
|
||||||
}
|
}
|
||||||
@@ -588,7 +588,7 @@ void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Pri
|
|||||||
*/
|
*/
|
||||||
if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
|
if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
|
||||||
if (S->ConDesPrio[Type] != Prio) {
|
if (S->ConDesPrio[Type] != Prio) {
|
||||||
Error ("Redeclaration mismatch for symbol '%m%p'", GetSymName (S));
|
Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
S->ConDesPrio[Type] = Prio;
|
S->ConDesPrio[Type] = Prio;
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Duplicate scope name */
|
/* Duplicate scope name */
|
||||||
Internal ("Duplicate scope name: '%m%p'", Name);
|
Internal ("Duplicate scope name: `%m%p'", Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,7 +216,7 @@ void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
|
|||||||
|
|
||||||
/* Check if the scope has been defined before */
|
/* Check if the scope has been defined before */
|
||||||
if (CurrentScope->Flags & ST_DEFINED) {
|
if (CurrentScope->Flags & ST_DEFINED) {
|
||||||
Error ("Duplicate scope '%m%p'", ScopeName);
|
Error ("Duplicate scope `%m%p'", ScopeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -502,7 +502,7 @@ static void SymCheckUndefined (SymEntry* S)
|
|||||||
if (Sym->Flags & SF_IMPORT) {
|
if (Sym->Flags & SF_IMPORT) {
|
||||||
/* The symbol is already marked as import */
|
/* The symbol is already marked as import */
|
||||||
LIError (&S->RefLines,
|
LIError (&S->RefLines,
|
||||||
"Symbol '%s' is already an import",
|
"Symbol `%s' is already an import",
|
||||||
GetString (Sym->Name));
|
GetString (Sym->Name));
|
||||||
}
|
}
|
||||||
if ((Sym->Flags & SF_EXPORT) == 0) {
|
if ((Sym->Flags & SF_EXPORT) == 0) {
|
||||||
@@ -516,7 +516,7 @@ static void SymCheckUndefined (SymEntry* S)
|
|||||||
if (Sym->AddrSize > Sym->ExportSize) {
|
if (Sym->AddrSize > Sym->ExportSize) {
|
||||||
/* We're exporting a symbol smaller than it actually is */
|
/* We're exporting a symbol smaller than it actually is */
|
||||||
LIWarning (&Sym->DefLines, 1,
|
LIWarning (&Sym->DefLines, 1,
|
||||||
"Symbol '%m%p' is %s but exported %s",
|
"Symbol `%m%p' is %s but exported %s",
|
||||||
GetSymName (Sym),
|
GetSymName (Sym),
|
||||||
AddrSizeToStr (Sym->AddrSize),
|
AddrSizeToStr (Sym->AddrSize),
|
||||||
AddrSizeToStr (Sym->ExportSize));
|
AddrSizeToStr (Sym->ExportSize));
|
||||||
@@ -541,7 +541,7 @@ static void SymCheckUndefined (SymEntry* S)
|
|||||||
if (S->Flags & SF_EXPORT) {
|
if (S->Flags & SF_EXPORT) {
|
||||||
/* We will not auto-import an export */
|
/* We will not auto-import an export */
|
||||||
LIError (&S->RefLines,
|
LIError (&S->RefLines,
|
||||||
"Exported symbol '%m%p' was never defined",
|
"Exported symbol `%m%p' was never defined",
|
||||||
GetSymName (S));
|
GetSymName (S));
|
||||||
} else {
|
} else {
|
||||||
if (AutoImport) {
|
if (AutoImport) {
|
||||||
@@ -554,7 +554,7 @@ static void SymCheckUndefined (SymEntry* S)
|
|||||||
} else {
|
} else {
|
||||||
/* Error */
|
/* Error */
|
||||||
LIError (&S->RefLines,
|
LIError (&S->RefLines,
|
||||||
"Symbol '%m%p' is undefined",
|
"Symbol `%m%p' is undefined",
|
||||||
GetSymName (S));
|
GetSymName (S));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -573,13 +573,13 @@ void SymCheck (void)
|
|||||||
if (CurrentScope->Label) {
|
if (CurrentScope->Label) {
|
||||||
/* proc has a label indicating the line it was opened. */
|
/* proc has a label indicating the line it was opened. */
|
||||||
LIError (&CurrentScope->Label->DefLines,
|
LIError (&CurrentScope->Label->DefLines,
|
||||||
"Local proc '%s' was not closed",
|
"Local proc `%s' was not closed",
|
||||||
GetString (CurrentScope->Name));
|
GetString (CurrentScope->Name));
|
||||||
} else {
|
} else {
|
||||||
/* scope has no label to track a line number, uses end-of-document line instead.
|
/* scope has no label to track a line number, uses end-of-document line instead.
|
||||||
** Anonymous scopes will reveal their internal automatic name.
|
** Anonymous scopes will reveal their internal automatic name.
|
||||||
*/
|
*/
|
||||||
Error ("Local scope '%s' was not closed",
|
Error ("Local scope `%s' was not closed",
|
||||||
GetString (CurrentScope->Name));
|
GetString (CurrentScope->Name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -627,7 +627,7 @@ void SymCheck (void)
|
|||||||
ReleaseFullLineInfo (&S->RefLines);
|
ReleaseFullLineInfo (&S->RefLines);
|
||||||
} else if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
|
} else if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
|
||||||
LIWarning (&S->DefLines, 2,
|
LIWarning (&S->DefLines, 2,
|
||||||
"Symbol '%m%p' is defined but never used",
|
"Symbol `%m%p' is defined but never used",
|
||||||
GetSymName (S));
|
GetSymName (S));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +636,7 @@ void SymCheck (void)
|
|||||||
if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
|
if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
|
||||||
/* Imported symbol is not referenced */
|
/* Imported symbol is not referenced */
|
||||||
LIWarning (&S->DefLines, 2,
|
LIWarning (&S->DefLines, 2,
|
||||||
"Symbol '%m%p' is imported but never used",
|
"Symbol `%m%p' is imported but never used",
|
||||||
GetSymName (S));
|
GetSymName (S));
|
||||||
} else {
|
} else {
|
||||||
/* Give the import an id, count imports */
|
/* Give the import an id, count imports */
|
||||||
@@ -664,7 +664,7 @@ void SymCheck (void)
|
|||||||
} else if (S->AddrSize > S->ExportSize) {
|
} else if (S->AddrSize > S->ExportSize) {
|
||||||
/* We're exporting a symbol smaller than it actually is */
|
/* We're exporting a symbol smaller than it actually is */
|
||||||
LIWarning (&S->DefLines, 1,
|
LIWarning (&S->DefLines, 1,
|
||||||
"Symbol '%m%p' is %s but exported %s",
|
"Symbol `%m%p' is %s but exported %s",
|
||||||
GetSymName (S),
|
GetSymName (S),
|
||||||
AddrSizeToStr (S->AddrSize),
|
AddrSizeToStr (S->AddrSize),
|
||||||
AddrSizeToStr (S->ExportSize));
|
AddrSizeToStr (S->ExportSize));
|
||||||
@@ -684,7 +684,7 @@ void SymCheck (void)
|
|||||||
const FilePos* P = S->GuessedUse[S->AddrSize - 1];
|
const FilePos* P = S->GuessedUse[S->AddrSize - 1];
|
||||||
if (P) {
|
if (P) {
|
||||||
PWarning (P, 0,
|
PWarning (P, 0,
|
||||||
"Didn't use %s addressing for '%m%p'",
|
"Didn't use %s addressing for `%m%p'",
|
||||||
AddrSizeToStr (S->AddrSize),
|
AddrSizeToStr (S->AddrSize),
|
||||||
GetSymName (S));
|
GetSymName (S));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
<ClInclude Include="common\check.h" />
|
<ClInclude Include="common\check.h" />
|
||||||
<ClInclude Include="common\cmdline.h" />
|
<ClInclude Include="common\cmdline.h" />
|
||||||
<ClInclude Include="common\coll.h" />
|
<ClInclude Include="common\coll.h" />
|
||||||
|
<ClInclude Include="common\consprop.h" />
|
||||||
<ClInclude Include="common\cpu.h" />
|
<ClInclude Include="common\cpu.h" />
|
||||||
<ClInclude Include="common\debugflag.h" />
|
<ClInclude Include="common\debugflag.h" />
|
||||||
<ClInclude Include="common\exprdefs.h" />
|
<ClInclude Include="common\exprdefs.h" />
|
||||||
@@ -139,6 +140,7 @@
|
|||||||
<ClCompile Include="common\check.c" />
|
<ClCompile Include="common\check.c" />
|
||||||
<ClCompile Include="common\cmdline.c" />
|
<ClCompile Include="common\cmdline.c" />
|
||||||
<ClCompile Include="common\coll.c" />
|
<ClCompile Include="common\coll.c" />
|
||||||
|
<ClCompile Include="common\consprop.c" />
|
||||||
<ClCompile Include="common\cpu.c" />
|
<ClCompile Include="common\cpu.c" />
|
||||||
<ClCompile Include="common\debugflag.c" />
|
<ClCompile Include="common\debugflag.c" />
|
||||||
<ClCompile Include="common\exprdefs.c" />
|
<ClCompile Include="common\exprdefs.c" />
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* (C) 2026, Kugelfuhr */
|
/* (C) 2025, Kugelfuhr */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* This software is provided 'as-is', without any expressed or implied */
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
|||||||
213
src/common/consprop.c
Normal file
213
src/common/consprop.c
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* consprop.c */
|
||||||
|
/* */
|
||||||
|
/* Console properties */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2025, Kugelfuhr */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
# include <unistd.h>
|
||||||
|
#else
|
||||||
|
# include <windows.h>
|
||||||
|
# include <io.h>
|
||||||
|
# define isatty _isatty
|
||||||
|
# define STDOUT_FILENO 1
|
||||||
|
# define STDERR_FILENO 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "consprop.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Data */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static unsigned CodePage; /* Windows code page on startup */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* State variables */
|
||||||
|
static int IsTTY = 1; /* True if console is a tty */
|
||||||
|
static int IsUTF8 = 1; /* True if console is in UTF-8 mode */
|
||||||
|
static int Color = 0; /* True if we should use color */
|
||||||
|
static ColorMode CMode = CM_AUTO; /* Current color mode */
|
||||||
|
|
||||||
|
/* ANSI escape sequences for color */
|
||||||
|
const char CP_ColorSeq[CC_COUNT][2][8] = {
|
||||||
|
{ "", "\x1b[30m", }, /* Black */
|
||||||
|
{ "", "\x1b[31m", }, /* Red */
|
||||||
|
{ "", "\x1b[32m", }, /* Green */
|
||||||
|
{ "", "\x1b[33m", }, /* Brown */
|
||||||
|
{ "", "\x1b[34m", }, /* Blue */
|
||||||
|
{ "", "\x1b[35m", }, /* Magenta */
|
||||||
|
{ "", "\x1b[36m", }, /* Cyan */
|
||||||
|
{ "", "\x1b[37m", }, /* LightGray */
|
||||||
|
{ "", "\x1b[90m", }, /* Gray */
|
||||||
|
{ "", "\x1b[91m", }, /* BrightRed */
|
||||||
|
{ "", "\x1b[92m", }, /* BrightGreen */
|
||||||
|
{ "", "\x1b[93m", }, /* Yellow */
|
||||||
|
{ "", "\x1b[94m", }, /* BrightBlue */
|
||||||
|
{ "", "\x1b[95m", }, /* BrightMagenta */
|
||||||
|
{ "", "\x1b[96m", }, /* BrightCyan */
|
||||||
|
{ "", "\x1b[97m", }, /* White */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Box drawing sequences */
|
||||||
|
const char CP_BoxDrawingSeq[BD_COUNT][2][4] = {
|
||||||
|
{ "-", "\xE2\x94\x80", }, /* "─" - Horizontal */
|
||||||
|
{ "|", "\xE2\x94\x82", }, /* "│" - Vertical */
|
||||||
|
{ "+", "\xE2\x94\x8C", }, /* "┌" - ULCorner */
|
||||||
|
{ "+", "\xE2\x94\x94", }, /* "└" - LLCorner */
|
||||||
|
{ "+", "\xE2\x94\x90", }, /* "┐" - URCorner */
|
||||||
|
{ "+", "\xE2\x94\x98", }, /* "┘" - LRCorner */
|
||||||
|
{ "+", "\xE2\x94\x9C", }, /* "├" - VerticalRight */
|
||||||
|
{ "+", "\xE2\x94\xA4", }, /* "┤" - VerticalLeft */
|
||||||
|
{ "+", "\xE2\x94\xAC", }, /* "┬" - HorizontalDown */
|
||||||
|
{ "+", "\xE2\x94\xB4", }, /* "┴" - HorizontalUp */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Helpers */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static void Cleanup (void)
|
||||||
|
/* Cleanup on program exit */
|
||||||
|
{
|
||||||
|
SetConsoleOutputCP (CodePage);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CP_Init (void)
|
||||||
|
/* Init console properties. Must be called before using any other function or
|
||||||
|
** data from this module.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
IsTTY = (isatty (STDOUT_FILENO) && isatty (STDERR_FILENO));
|
||||||
|
CP_SetColorMode (CMode);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (IsTTY) {
|
||||||
|
CodePage = GetConsoleOutputCP ();
|
||||||
|
IsUTF8 = (int) SetConsoleOutputCP (CP_UTF8);
|
||||||
|
if (IsUTF8) {
|
||||||
|
/* Switch the code page back on exit */
|
||||||
|
atexit (Cleanup);
|
||||||
|
}
|
||||||
|
if (Color) {
|
||||||
|
HANDLE StdOut = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||||
|
if (StdOut != INVALID_HANDLE_VALUE) {
|
||||||
|
DWORD Mode;
|
||||||
|
if (GetConsoleMode (StdOut, &Mode)) {
|
||||||
|
Mode |= ENABLE_PROCESSED_OUTPUT |
|
||||||
|
ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
SetConsoleMode (StdOut, Mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int CP_IsTTY (void)
|
||||||
|
/* Return true if console output goes to a tty */
|
||||||
|
{
|
||||||
|
return IsTTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int CP_IsUTF8 (void)
|
||||||
|
/* Return true if the console supports UTF-8 */
|
||||||
|
{
|
||||||
|
return IsUTF8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int CP_HasColor (void)
|
||||||
|
/* Return true if the console supports color and it should be used */
|
||||||
|
{
|
||||||
|
return Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ColorMode CP_GetColorMode (void)
|
||||||
|
/* Return the current color mode */
|
||||||
|
{
|
||||||
|
return CMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CP_SetColorMode (ColorMode M)
|
||||||
|
/* Set the color mode */
|
||||||
|
{
|
||||||
|
CMode = M;
|
||||||
|
switch (CMode) {
|
||||||
|
case CM_AUTO: Color = IsTTY; break;
|
||||||
|
case CM_ON: Color = 1; break;
|
||||||
|
default: Color = 0; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CP_DisableUTF8 (void)
|
||||||
|
/* Disable UTF-8 support */
|
||||||
|
{
|
||||||
|
IsUTF8 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CP_EnableUTF8 (void)
|
||||||
|
/* Enable UTF-8 support */
|
||||||
|
{
|
||||||
|
IsUTF8 = 1;
|
||||||
|
}
|
||||||
174
src/common/consprop.h
Normal file
174
src/common/consprop.h
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* consprop.h */
|
||||||
|
/* */
|
||||||
|
/* Console properties */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2025, Kugelfuhr */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CONSPROP_H
|
||||||
|
#define CONSPROP_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "check.h"
|
||||||
|
#include "consprop.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Data */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Color mode for the program */
|
||||||
|
enum ColorMode { CM_OFF, CM_AUTO, CM_ON };
|
||||||
|
typedef enum ColorMode ColorMode;
|
||||||
|
|
||||||
|
/* Colors */
|
||||||
|
enum ConsoleColor {
|
||||||
|
CC_BLACK, CC_RED, CC_GREEN, CC_BROWN,
|
||||||
|
CC_BLUE, CC_MAGENTA, CC_CYAN, CC_LIGHTGRAY,
|
||||||
|
CC_GRAY, CC_BRIGHTRED, CC_BRIGHTGREEN, CC_YELLOW,
|
||||||
|
CC_BRIGHTBLUE, CC_BRIGHTMAGENTA, CC_BRIGHTCYAN, CC_WHITE,
|
||||||
|
CC_COUNT, /* Number of colors */
|
||||||
|
};
|
||||||
|
typedef enum ConsoleColor ConsoleColor;
|
||||||
|
|
||||||
|
/* Box drawing characters */
|
||||||
|
enum BoxDrawing {
|
||||||
|
BD_HORIZONTAL,
|
||||||
|
BD_VERTICAL,
|
||||||
|
BD_ULCORNER,
|
||||||
|
BD_LLCORNER,
|
||||||
|
BD_URCORNER,
|
||||||
|
BD_LRCORNER,
|
||||||
|
BD_RVERTICAL,
|
||||||
|
BD_LVERTICAL,
|
||||||
|
BD_DHORIZONTAL,
|
||||||
|
BD_UHORIZONTAL,
|
||||||
|
BD_COUNT, /* Number of available box drawing chars */
|
||||||
|
};
|
||||||
|
typedef enum BoxDrawing BoxDrawing;
|
||||||
|
|
||||||
|
/* ANSI escape sequences for color - don't use directly */
|
||||||
|
extern const char CP_ColorSeq[CC_COUNT][2][8];
|
||||||
|
|
||||||
|
/* Box drawing characters - don't use directly */
|
||||||
|
extern const char CP_BoxDrawingSeq[BD_COUNT][2][4];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CP_Init (void);
|
||||||
|
/* Init console properties. Must be called before using any other function or
|
||||||
|
** data from this module.
|
||||||
|
**/
|
||||||
|
|
||||||
|
int CP_IsTTY (void);
|
||||||
|
/* Return true if console output goes to a tty */
|
||||||
|
|
||||||
|
int CP_IsUTF8 (void);
|
||||||
|
/* Return true if the console supports UTF-8 */
|
||||||
|
|
||||||
|
int CP_HasColor (void);
|
||||||
|
/* Return true if the console supports color and it should be used */
|
||||||
|
|
||||||
|
ColorMode CP_GetColorMode (void);
|
||||||
|
/* Return the current color mode */
|
||||||
|
|
||||||
|
void CP_SetColorMode (ColorMode M);
|
||||||
|
/* Set the color mode */
|
||||||
|
|
||||||
|
void CP_DisableUTF8 (void);
|
||||||
|
/* Disable UTF-8 support */
|
||||||
|
|
||||||
|
void CP_EnableUTF8 (void);
|
||||||
|
/* Enable UTF-8 support */
|
||||||
|
|
||||||
|
static inline const char* CP_Color (ConsoleColor C)
|
||||||
|
/* Return the ANSI escape sequence for a specific color or an empty string */
|
||||||
|
{
|
||||||
|
PRECONDITION (C >= 0 && C < CC_COUNT);
|
||||||
|
return CP_ColorSeq[C][CP_HasColor ()];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char* CP_Reset (void)
|
||||||
|
/* Return the ANSI escape sequence to reset the colors or an empty string */
|
||||||
|
{
|
||||||
|
return CP_HasColor () ? "\x1b[0m" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return specific colors */
|
||||||
|
static inline const char* CP_Black (void) { return CP_Color (CC_BLACK); }
|
||||||
|
static inline const char* CP_Red (void) { return CP_Color (CC_RED); }
|
||||||
|
static inline const char* CP_Green (void) { return CP_Color (CC_GREEN); }
|
||||||
|
static inline const char* CP_Brown (void) { return CP_Color (CC_BROWN); }
|
||||||
|
static inline const char* CP_Blue (void) { return CP_Color (CC_BLUE); }
|
||||||
|
static inline const char* CP_Magenta (void) { return CP_Color (CC_MAGENTA); }
|
||||||
|
static inline const char* CP_Cyan (void) { return CP_Color (CC_CYAN); }
|
||||||
|
static inline const char* CP_LightGray (void) { return CP_Color (CC_LIGHTGRAY); }
|
||||||
|
static inline const char* CP_Gray (void) { return CP_Color (CC_GRAY); }
|
||||||
|
static inline const char* CP_BrightRed (void) { return CP_Color (CC_BRIGHTRED); }
|
||||||
|
static inline const char* CP_BrightGreen (void) { return CP_Color (CC_BRIGHTGREEN); }
|
||||||
|
static inline const char* CP_Yellow (void) { return CP_Color (CC_YELLOW); }
|
||||||
|
static inline const char* CP_BrightBlue (void) { return CP_Color (CC_BRIGHTBLUE); }
|
||||||
|
static inline const char* CP_BrightMagenta (void) { return CP_Color (CC_BRIGHTMAGENTA); }
|
||||||
|
static inline const char* CP_BrightCyan (void) { return CP_Color (CC_BRIGHTCYAN); }
|
||||||
|
static inline const char* CP_White (void) { return CP_Color (CC_WHITE); }
|
||||||
|
|
||||||
|
static inline const char* CP_BoxDrawing (BoxDrawing B)
|
||||||
|
/* Return the UTF-8 sequence for the box drawing characters */
|
||||||
|
{
|
||||||
|
PRECONDITION (B >= 0 && B < BD_COUNT);
|
||||||
|
return CP_BoxDrawingSeq[B][CP_IsUTF8 ()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return specific box drawing character sequences */
|
||||||
|
static inline const char* CP_Horizontal (void) { return CP_BoxDrawing (BD_HORIZONTAL); }
|
||||||
|
static inline const char* CP_Vertical (void) { return CP_BoxDrawing (BD_VERTICAL); }
|
||||||
|
static inline const char* CP_ULCorner (void) { return CP_BoxDrawing (BD_ULCORNER); }
|
||||||
|
static inline const char* CP_LLCorner (void) { return CP_BoxDrawing (BD_LLCORNER); }
|
||||||
|
static inline const char* CP_URCorner (void) { return CP_BoxDrawing (BD_URCORNER); }
|
||||||
|
static inline const char* CP_LRCorner (void) { return CP_BoxDrawing (BD_LRCORNER); }
|
||||||
|
static inline const char* CP_VerticalRight (void) { return CP_BoxDrawing (BD_RVERTICAL); }
|
||||||
|
static inline const char* CP_VerticalLeft (void) { return CP_BoxDrawing (BD_LVERTICAL); }
|
||||||
|
static inline const char* CP_HorizontalDown (void) { return CP_BoxDrawing (BD_DHORIZONTAL); }
|
||||||
|
static inline const char* CP_HorizontalUp (void) { return CP_BoxDrawing (BD_UHORIZONTAL); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* End of consprop.h */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,2 +1 @@
|
|||||||
lda |
|
lda |
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ $(WORKDIR)/$1.bin: $1.s $(ISEQUAL)
|
|||||||
|
|
||||||
# compile without generating listing
|
# compile without generating listing
|
||||||
ifeq ($(wildcard control/$1.err),)
|
ifeq ($(wildcard control/$1.err),)
|
||||||
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2> $$(@:.bin=.err2)
|
$(CA65) -t none --no-utf8 -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2> $$(@:.bin=.err2)
|
||||||
ifeq ($(wildcard control/$1.no-ld65),)
|
ifeq ($(wildcard control/$1.no-ld65),)
|
||||||
ifeq ($(wildcard $1.cfg),)
|
ifeq ($(wildcard $1.cfg),)
|
||||||
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) 2> $$(@:.bin=.ld65-err2)
|
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) 2> $$(@:.bin=.ld65-err2)
|
||||||
@@ -82,7 +82,7 @@ else
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2> $$(@:.bin=.err2) || $(TRUE)
|
$(CA65) -t none --no-utf8 -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2> $$(@:.bin=.err2) || $(TRUE)
|
||||||
ifeq ($(wildcard control/$1.no-ld65),)
|
ifeq ($(wildcard control/$1.no-ld65),)
|
||||||
ifeq ($(wildcard $1.cfg),)
|
ifeq ($(wildcard $1.cfg),)
|
||||||
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) 2> $$(@:.bin=.ld65-err2) || $(TRUE)
|
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) 2> $$(@:.bin=.ld65-err2) || $(TRUE)
|
||||||
@@ -144,7 +144,7 @@ endif
|
|||||||
|
|
||||||
# compile with listing file
|
# compile with listing file
|
||||||
ifeq ($(wildcard control/$1.err),)
|
ifeq ($(wildcard control/$1.err),)
|
||||||
$(CA65) -t none -l $$(@:.bin=.list-lst) -o $$(@:.bin=.list-o) $$< > $$(@:.bin=.list-err) 2> $$(@:.bin=.list-err2)
|
$(CA65) -t none --no-utf8 -l $$(@:.bin=.list-lst) -o $$(@:.bin=.list-o) $$< > $$(@:.bin=.list-err) 2> $$(@:.bin=.list-err2)
|
||||||
ifeq ($(wildcard control/$1.no-ld65),)
|
ifeq ($(wildcard control/$1.no-ld65),)
|
||||||
ifeq ($(wildcard $1.cfg),)
|
ifeq ($(wildcard $1.cfg),)
|
||||||
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib > $$(@:.bin=.list-ld65-err) 2> $$(@:.bin=.list-ld65-err2)
|
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib > $$(@:.bin=.list-ld65-err) 2> $$(@:.bin=.list-ld65-err2)
|
||||||
@@ -153,7 +153,7 @@ else
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
$(CA65) -t none -l $$(@:.bin=.list-lst) -o $$(@:.bin=.list-o) $$< > $$(@:.bin=.list-err) 2> $$(@:.bin=.list-err2) || $(TRUE)
|
$(CA65) -t none --no-utf8 -l $$(@:.bin=.list-lst) -o $$(@:.bin=.list-o) $$< > $$(@:.bin=.list-err) 2> $$(@:.bin=.list-err2) || $(TRUE)
|
||||||
ifeq ($(wildcard control/$1.no-ld65),)
|
ifeq ($(wildcard control/$1.no-ld65),)
|
||||||
ifeq ($(wildcard $1.cfg),)
|
ifeq ($(wildcard $1.cfg),)
|
||||||
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib > $$(@:.bin=.list-ld65-err) 2> $$(@:.bin=.list-ld65-err2) || $(TRUE)
|
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib > $$(@:.bin=.list-ld65-err) 2> $$(@:.bin=.list-ld65-err2) || $(TRUE)
|
||||||
|
|||||||
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