mirror of
https://github.com/cc65/cc65.git
synced 2025-01-16 13:31:16 +00:00
Support for preprocessing info file via cpp or m4.
This commit is contained in:
parent
6c320f7d65
commit
2b25329423
@ -53,6 +53,7 @@ Short options:
|
||||
-o name Name the output file
|
||||
-v Increase verbosity
|
||||
-F Add formfeeds to the output
|
||||
-s Accept line markers in the info file
|
||||
-S addr Set the start/load address
|
||||
-V Print the disassembler version
|
||||
|
||||
@ -70,6 +71,7 @@ Long options:
|
||||
--mnemonic-column n Specify mnemonic start column
|
||||
--pagelength n Set the page length for the listing
|
||||
--start-addr addr Set the start/load address
|
||||
--sync-lines Accept line markers in the info file
|
||||
--text-column n Specify text start column
|
||||
--verbose Increase verbosity
|
||||
--version Print the disassembler version
|
||||
@ -205,6 +207,17 @@ Here is a description of all the command line options:
|
||||
start address is specified, $10000 minus the size of the input file is used.
|
||||
|
||||
|
||||
<label id="option--sync-lines">
|
||||
<tag><tt>-s, --sync-lines</tt></tag>
|
||||
|
||||
Accept line markers in the info file in the following syntax:
|
||||
<tscreen><verb>
|
||||
#line <lineno> ["<filename>"]
|
||||
# <lineno> "<filename>" [<flag>] ...
|
||||
</verb></tscreen>
|
||||
This option is intended for preprocessing info files with "cpp" or "m4".
|
||||
|
||||
|
||||
<label id="option--text-column">
|
||||
<tag><tt>--text-column n</tt></tag>
|
||||
|
||||
@ -299,9 +312,10 @@ anything). Each attribute is terminated by a semicolon.
|
||||
|
||||
<sect1>Comments<p>
|
||||
|
||||
Comments start with a hash mark (<tt/#/); and, extend from the position of
|
||||
the mark to the end of the current line. Hash marks inside of strings will
|
||||
<em/not/ start a comment, of course.
|
||||
Comments start with a hash mark (<tt/#/) or a double slashe (<tt>//</tt>);
|
||||
and, extend from the position of the mark to the end of the current line.
|
||||
Hash marks or double slashes inside of strings will <em/not/ start a comment,
|
||||
of course.
|
||||
|
||||
|
||||
<sect1>Specifying global options<label id="global-options"><p>
|
||||
|
@ -82,6 +82,7 @@ static void Usage (void)
|
||||
" -v\t\t\tIncrease verbosity\n"
|
||||
" -F\t\t\tAdd formfeeds to the output\n"
|
||||
" -S addr\t\tSet the start/load address\n"
|
||||
" -s\t\t\tAccept line markers in the info file\n"
|
||||
" -V\t\t\tPrint the disassembler version\n"
|
||||
"\n"
|
||||
"Long options:\n"
|
||||
@ -98,6 +99,7 @@ static void Usage (void)
|
||||
" --mnemonic-column n\tSpecify mnemonic start column\n"
|
||||
" --pagelength n\tSet the page length for the listing\n"
|
||||
" --start-addr addr\tSet the start/load address\n"
|
||||
" --sync-lines\t\tAccept line markers in the info file\n"
|
||||
" --text-column n\tSpecify text start column\n"
|
||||
" --verbose\t\tIncrease verbosity\n"
|
||||
" --version\t\tPrint the disassembler version\n",
|
||||
@ -312,6 +314,15 @@ static void OptStartAddr (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptSyncLines (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Handle the --sync-lines option */
|
||||
{
|
||||
InfoSyncLines = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptTextColumn (const char* Opt, const char* Arg)
|
||||
/* Handle the --text-column option */
|
||||
{
|
||||
@ -539,6 +550,7 @@ int main (int argc, char* argv [])
|
||||
{ "--mnemonic-column", 1, OptMnemonicColumn },
|
||||
{ "--pagelength", 1, OptPageLength },
|
||||
{ "--start-addr", 1, OptStartAddr },
|
||||
{ "--sync-lines", 0, OptSyncLines },
|
||||
{ "--text-column", 1, OptTextColumn },
|
||||
{ "--verbose", 0, OptVerbose },
|
||||
{ "--version", 0, OptVersion },
|
||||
@ -589,6 +601,10 @@ int main (int argc, char* argv [])
|
||||
OptStartAddr (Arg, GetArg (&I, 2));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
OptSyncLines (Arg, 0);
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
OptVersion (Arg, 0);
|
||||
break;
|
||||
|
@ -41,6 +41,8 @@
|
||||
/* common */
|
||||
#include "chartype.h"
|
||||
#include "xsprintf.h"
|
||||
#include "xmalloc.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
/* ld65 */
|
||||
#include "global.h"
|
||||
@ -72,7 +74,10 @@ static int C = ' ';
|
||||
static unsigned InputLine = 1;
|
||||
static unsigned InputCol = 0;
|
||||
static FILE* InputFile = 0;
|
||||
static char* InputSrcName = 0;
|
||||
|
||||
/* Options */
|
||||
unsigned char InfoSyncLines = 0;
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -91,7 +96,8 @@ void InfoWarning (const char* Format, ...)
|
||||
xvsprintf (Buf, sizeof (Buf), Format, ap);
|
||||
va_end (ap);
|
||||
|
||||
Warning ("%s(%u): %s", InfoFile, InfoErrorLine, Buf);
|
||||
fprintf (stderr, "%s(%u): Warning: %s\n",
|
||||
InputSrcName, InfoErrorLine, Buf);
|
||||
}
|
||||
|
||||
|
||||
@ -106,7 +112,9 @@ void InfoError (const char* Format, ...)
|
||||
xvsprintf (Buf, sizeof (Buf), Format, ap);
|
||||
va_end (ap);
|
||||
|
||||
Error ("%s(%u): %s", InfoFile, InfoErrorLine, Buf);
|
||||
fprintf (stderr, "%s(%u): Error: %s\n",
|
||||
InputSrcName, InfoErrorLine, Buf);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
@ -149,17 +157,171 @@ static unsigned DigitVal (int C)
|
||||
|
||||
|
||||
|
||||
static void SkipBlanks (int SingleLine)
|
||||
{
|
||||
while (C != EOF && (!SingleLine || C != '\n') && IsSpace (C)) {
|
||||
NextChar ();
|
||||
}
|
||||
}
|
||||
|
||||
static long GetDecimalToken ()
|
||||
{
|
||||
long Value = 0;
|
||||
|
||||
while (C != EOF && IsDigit (C)) {
|
||||
Value = Value * 10 + DigitVal (C);
|
||||
NextChar ();
|
||||
}
|
||||
return Value;
|
||||
}
|
||||
|
||||
static int GetEncodedChar (char *Buf, unsigned *IPtr, unsigned Size)
|
||||
{
|
||||
char Decoded = 0;
|
||||
int Count;
|
||||
|
||||
if (C == EOF) {
|
||||
return -1;
|
||||
} else if (C != '\\') {
|
||||
Decoded = C;
|
||||
NextChar ();
|
||||
goto Store;
|
||||
}
|
||||
NextChar (); /* consume '\\' */
|
||||
if (C == EOF) {
|
||||
return -1;
|
||||
} else if (IsODigit (C)) {
|
||||
Count = 3;
|
||||
do {
|
||||
Decoded = Decoded * 8 + DigitVal (C);
|
||||
NextChar ();
|
||||
--Count;
|
||||
} while (Count > 0 && C != EOF && IsODigit (C));
|
||||
} else if (C == 'x') {
|
||||
NextChar (); /* consume 'x' */
|
||||
Count = 2;
|
||||
while (Count > 0 && C != EOF && IsXDigit (C)) {
|
||||
Decoded = Decoded * 16 + DigitVal (C);
|
||||
NextChar ();
|
||||
--Count;
|
||||
}
|
||||
} else {
|
||||
switch (C) {
|
||||
case '"': case '\'': case '\\':
|
||||
Decoded = C; break;
|
||||
case 't': Decoded = '\t'; break;
|
||||
case 'r': Decoded = '\r'; break;
|
||||
case 'n': Decoded = '\n'; break;
|
||||
default: return -1;
|
||||
}
|
||||
NextChar ();
|
||||
}
|
||||
Store:
|
||||
if (*IPtr < Size - 1) {
|
||||
Buf [(*IPtr)++] = Decoded;
|
||||
}
|
||||
Buf [*IPtr] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void LineMarkerOrComment ()
|
||||
/* Handle a line beginning with '#'. Possible interpretations are:
|
||||
* - #line <lineno> ["<filename>"] (C preprocessor input)
|
||||
* - # <lineno> "<filename>" [<flag>]... (gcc preprocessor output)
|
||||
* - #<comment>
|
||||
*/
|
||||
{
|
||||
unsigned long LineNo = 0;
|
||||
int LineDirective = 0;
|
||||
StrBuf SrcNameBuf = AUTO_STRBUF_INITIALIZER;
|
||||
|
||||
/* Skip the first "# " */
|
||||
NextChar ();
|
||||
SkipBlanks (1);
|
||||
|
||||
/* Check "line" */
|
||||
if (C == 'l') {
|
||||
char MaybeLine [6];
|
||||
unsigned I;
|
||||
for (I = 0; I < sizeof MaybeLine - 1 && C != EOF && IsAlNum (C); ++I) {
|
||||
MaybeLine [I] = C;
|
||||
NextChar ();
|
||||
}
|
||||
MaybeLine [I] = 0;
|
||||
if (strcmp (MaybeLine, "line") != 0) {
|
||||
goto NotMarker;
|
||||
}
|
||||
LineDirective = 1;
|
||||
SkipBlanks (1);
|
||||
}
|
||||
|
||||
/* Get line number */
|
||||
if (C == EOF || !IsDigit (C)) {
|
||||
goto NotMarker;
|
||||
}
|
||||
LineNo = GetDecimalToken ();
|
||||
SkipBlanks (1);
|
||||
|
||||
/* Get the source file name */
|
||||
if (C != '\"') {
|
||||
/* The source file name is missing */
|
||||
if (LineDirective && C == '\n') {
|
||||
/* got #line <lineno> */
|
||||
NextChar ();
|
||||
InputLine = LineNo;
|
||||
goto Last;
|
||||
} else {
|
||||
goto NotMarker;
|
||||
}
|
||||
}
|
||||
NextChar ();
|
||||
while (C != EOF && C != '\n' && C != '\"') {
|
||||
char DecodeBuf [2];
|
||||
unsigned I = 0;
|
||||
if (GetEncodedChar (DecodeBuf, &I, sizeof DecodeBuf) < 0) {
|
||||
goto BadMarker;
|
||||
}
|
||||
SB_AppendBuf (&SrcNameBuf, DecodeBuf, I);
|
||||
}
|
||||
if (C != '\"') {
|
||||
goto BadMarker;
|
||||
}
|
||||
NextChar ();
|
||||
|
||||
/* Ignore until the end of line */
|
||||
while (C != EOF && C != '\n') {
|
||||
NextChar ();
|
||||
}
|
||||
|
||||
/* Accepted a line marker */
|
||||
SB_Terminate (&SrcNameBuf);
|
||||
xfree (InputSrcName);
|
||||
InputSrcName = SB_GetBuf (&SrcNameBuf);
|
||||
SB_Init (&SrcNameBuf);
|
||||
InputLine = (unsigned)LineNo;
|
||||
NextChar ();
|
||||
goto Last;
|
||||
|
||||
BadMarker:
|
||||
InfoWarning ("Bad line marker");
|
||||
NotMarker:
|
||||
while (C != EOF && C != '\n') {
|
||||
NextChar ();
|
||||
}
|
||||
NextChar ();
|
||||
Last:
|
||||
SB_Done (&SrcNameBuf);
|
||||
}
|
||||
|
||||
void InfoNextTok (void)
|
||||
/* Read the next token from the input stream */
|
||||
{
|
||||
unsigned I;
|
||||
int Esc;
|
||||
char DecodeBuf [2];
|
||||
|
||||
Again:
|
||||
/* Skip whitespace */
|
||||
while (IsSpace (C)) {
|
||||
NextChar ();
|
||||
}
|
||||
SkipBlanks (0);
|
||||
|
||||
/* Remember the current position */
|
||||
InfoErrorLine = InputLine;
|
||||
@ -198,11 +360,7 @@ Again:
|
||||
|
||||
/* Decimal number? */
|
||||
if (IsDigit (C)) {
|
||||
InfoIVal = 0;
|
||||
while (IsDigit (C)) {
|
||||
InfoIVal = InfoIVal * 10 + DigitVal (C);
|
||||
NextChar ();
|
||||
}
|
||||
InfoIVal = GetDecimalToken ();
|
||||
InfoTok = INFOTOK_INTCON;
|
||||
return;
|
||||
}
|
||||
@ -248,38 +406,31 @@ Again:
|
||||
case '\"':
|
||||
NextChar ();
|
||||
I = 0;
|
||||
while (C != '\"') {
|
||||
Esc = (C == '\\');
|
||||
if (Esc) {
|
||||
NextChar ();
|
||||
}
|
||||
if (C == EOF || C == '\n') {
|
||||
InfoError ("Unterminated string");
|
||||
}
|
||||
if (Esc) {
|
||||
switch (C) {
|
||||
case '\"': C = '\"'; break;
|
||||
case '\'': C = '\''; break;
|
||||
default: InfoError ("Invalid escape char: %c", C);
|
||||
while (C != EOF && C != '\"') {
|
||||
if (GetEncodedChar (InfoSVal, &I, sizeof InfoSVal) < 0) {
|
||||
if (C == EOF) {
|
||||
InfoError ("Unterminated string");
|
||||
} else {
|
||||
InfoError ("Invalid escape char: %c", C);
|
||||
}
|
||||
}
|
||||
if (I < CFG_MAX_IDENT_LEN) {
|
||||
InfoSVal [I++] = C;
|
||||
}
|
||||
NextChar ();
|
||||
}
|
||||
NextChar ();
|
||||
InfoSVal [I] = '\0';
|
||||
if (C != '\"') {
|
||||
InfoError ("Unterminated string");
|
||||
}
|
||||
NextChar ();
|
||||
InfoTok = INFOTOK_STRCON;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
NextChar ();
|
||||
if (C == EOF || IsControl (C)) {
|
||||
if (C == EOF || IsControl (C) || C == '\'') {
|
||||
InfoError ("Invalid character constant");
|
||||
}
|
||||
InfoIVal = C;
|
||||
NextChar ();
|
||||
if (GetEncodedChar (DecodeBuf, &I, sizeof DecodeBuf) < 0 || I != 1) {
|
||||
InfoError ("Invalid character constant");
|
||||
}
|
||||
InfoIVal = DecodeBuf [0];
|
||||
if (C != '\'') {
|
||||
InfoError ("Unterminated character constant");
|
||||
}
|
||||
@ -288,8 +439,13 @@ Again:
|
||||
break;
|
||||
|
||||
case '#':
|
||||
/* Comment */
|
||||
while (C != '\n' && C != EOF) {
|
||||
/* # lineno "sourcefile" or # comment */
|
||||
if (InfoSyncLines && InputCol == 1) {
|
||||
LineMarkerOrComment ();
|
||||
} else {
|
||||
do {
|
||||
NextChar ();
|
||||
} while (C != EOF && C != '\n');
|
||||
NextChar ();
|
||||
}
|
||||
if (C != EOF) {
|
||||
@ -298,6 +454,21 @@ Again:
|
||||
InfoTok = INFOTOK_EOF;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
/* C++ style comment */
|
||||
NextChar ();
|
||||
if (C != '/') {
|
||||
InfoError ("Invalid token `/'");
|
||||
}
|
||||
do {
|
||||
NextChar ();
|
||||
} while (C != '\n' && C != EOF);
|
||||
if (C != EOF) {
|
||||
goto Again;
|
||||
}
|
||||
InfoTok = INFOTOK_EOF;
|
||||
break;
|
||||
|
||||
case EOF:
|
||||
InfoTok = INFOTOK_EOF;
|
||||
break;
|
||||
@ -484,15 +655,19 @@ void InfoSetName (const char* Name)
|
||||
/* Set a name for a config file */
|
||||
{
|
||||
InfoFile = Name;
|
||||
xfree(InputSrcName);
|
||||
InputSrcName = xstrdup(Name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef unused
|
||||
const char* InfoGetName (void)
|
||||
/* Get the name of the config file */
|
||||
{
|
||||
return InfoFile? InfoFile : "";
|
||||
}
|
||||
#endif /* unused */
|
||||
|
||||
|
||||
|
||||
|
@ -138,6 +138,8 @@ extern long InfoIVal;
|
||||
extern unsigned InfoErrorLine;
|
||||
extern unsigned InfoErrorCol;
|
||||
|
||||
/* Options */
|
||||
extern unsigned char InfoSyncLines;
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
Loading…
x
Reference in New Issue
Block a user