From 3d8396b86f4d95cb0fd76ac1418c0d92e296b84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Ni=C3=B1o=20D=C3=ADaz?= Date: Sat, 8 Apr 2017 18:10:14 +0100 Subject: [PATCH 1/2] Remove progname variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error message shouldn't specify the name of the binary, that's supposed to be known by the caller. Update test reference outputs. Signed-off-by: Antonio Niño Díaz --- src/asm/main.c | 4 ---- src/extern/err.c | 10 ++++------ src/fix/main.c | 4 ---- src/gfx/main.c | 4 ---- src/link/main.c | 4 ---- test/asm/undefined-dot.out | 2 +- test/link/romx-tiny-no-t.out | 2 +- test/link/romx-tiny-t.out | 2 +- test/link/vram-fixed-dmg-mode-w.out | 2 +- test/link/vram-floating-dmg-mode-w.out | 2 +- test/link/wramx-dmg-mode-no-w.out | 2 +- test/link/wramx-dmg-mode-w.out | 2 +- 12 files changed, 11 insertions(+), 29 deletions(-) diff --git a/src/asm/main.c b/src/asm/main.c index 8423c029..ef7155a3 100644 --- a/src/asm/main.c +++ b/src/asm/main.c @@ -20,8 +20,6 @@ int cldefines_index; int cldefines_size; char **cldefines; -char *progname; - clock_t nStartClock, nEndClock; SLONG nLineNo; ULONG nTotalLines, nPass, nPC, nIFDepth, nErrors; @@ -301,8 +299,6 @@ main(int argc, char *argv[]) if (argc == 1) usage(); - progname = "rgbasm"; - /* yydebug=1; */ DefaultOptions.gbgfx[0] = '0'; diff --git a/src/extern/err.c b/src/extern/err.c index bfeced2b..77c653e0 100644 --- a/src/extern/err.c +++ b/src/extern/err.c @@ -26,11 +26,9 @@ #include #include "extern/err.h" -extern char *progname; - void rgbds_vwarn(const char *fmt, va_list ap) { - fprintf (stderr, "%s: warning", progname); + fprintf (stderr, "warning"); if (fmt) { fputs (": ", stderr); vfprintf(stderr, fmt, ap); @@ -41,7 +39,7 @@ void rgbds_vwarn(const char *fmt, va_list ap) void rgbds_vwarnx(const char *fmt, va_list ap) { - fprintf (stderr, "%s: warning", progname); + fprintf (stderr, "warning"); if (fmt) { fputs (": ", stderr); vfprintf(stderr, fmt, ap); @@ -51,7 +49,7 @@ void rgbds_vwarnx(const char *fmt, va_list ap) noreturn void rgbds_verr(int status, const char *fmt, va_list ap) { - fprintf (stderr, "%s: error", progname); + fprintf (stderr, "error"); if (fmt) { fputs (": ", stderr); vfprintf(stderr, fmt, ap); @@ -62,7 +60,7 @@ noreturn void rgbds_verr(int status, const char *fmt, va_list ap) noreturn void rgbds_verrx(int status, const char *fmt, va_list ap) { - fprintf (stderr, "%s: error", progname); + fprintf (stderr, "error"); if (fmt) { fputs (": ", stderr); vfprintf(stderr, fmt, ap); diff --git a/src/fix/main.c b/src/fix/main.c index 26d33877..f634ce57 100644 --- a/src/fix/main.c +++ b/src/fix/main.c @@ -23,8 +23,6 @@ #include "extern/err.h" -char *progname; - static void usage(void) { @@ -71,8 +69,6 @@ main(int argc, char *argv[]) int version; /* mask ROM version number */ int padvalue; /* to pad the rom with if it changes size */ - progname = "rgbfix"; - while ((ch = getopt(argc, argv, "Cci:jk:l:m:n:p:sr:t:v")) != -1) { switch (ch) { case 'C': diff --git a/src/gfx/main.c b/src/gfx/main.c index fac25d5d..cc8bca2a 100644 --- a/src/gfx/main.c +++ b/src/gfx/main.c @@ -19,8 +19,6 @@ #include #include "gfx/main.h" -char *progname; - static void usage(void) { @@ -41,8 +39,6 @@ main(int argc, char *argv[]) char *ext; const char *errmsg = "Warning: The PNG's %s setting is not the same as the setting defined on the command line."; - progname = "rgbgfx"; - if (argc == 1) { usage(); } diff --git a/src/link/main.c b/src/link/main.c index d602f77f..c24d0f6b 100644 --- a/src/link/main.c +++ b/src/link/main.c @@ -24,8 +24,6 @@ SLONG options = 0; SLONG fillchar = 0; char *smartlinkstartsymbol; -char *progname; - /* * Print the usagescreen * @@ -54,8 +52,6 @@ main(int argc, char *argv[]) if (argc == 1) usage(); - progname = "rgblink"; - while ((ch = getopt(argc, argv, "l:m:n:o:O:p:s:tw")) != -1) { switch (ch) { case 'l': diff --git a/test/asm/undefined-dot.out b/test/asm/undefined-dot.out index e1e4ffb6..c1966e4b 100644 --- a/test/asm/undefined-dot.out +++ b/test/asm/undefined-dot.out @@ -1,3 +1,3 @@ ERROR: undefined-dot.asm(3): '.' not defined -rgbasm: error: Assembly aborted in pass 2 (1 errors)! +error: Assembly aborted in pass 2 (1 errors)! diff --git a/test/link/romx-tiny-no-t.out b/test/link/romx-tiny-no-t.out index 700b9a74..dabf2904 100644 --- a/test/link/romx-tiny-no-t.out +++ b/test/link/romx-tiny-no-t.out @@ -1 +1 @@ -rgblink: error: Unable to place 'r0b' (ROM0 section) anywhere +error: Unable to place 'r0b' (ROM0 section) anywhere diff --git a/test/link/romx-tiny-t.out b/test/link/romx-tiny-t.out index e8fa3e82..ef714e24 100644 --- a/test/link/romx-tiny-t.out +++ b/test/link/romx-tiny-t.out @@ -1 +1 @@ -rgblink: error: ROMX sections can't be used with option -t. +error: ROMX sections can't be used with option -t. diff --git a/test/link/vram-fixed-dmg-mode-w.out b/test/link/vram-fixed-dmg-mode-w.out index 277c6954..1ed998ce 100644 --- a/test/link/vram-fixed-dmg-mode-w.out +++ b/test/link/vram-fixed-dmg-mode-w.out @@ -1 +1 @@ -rgblink: error: VRAM bank 1 can't be used with option -w. +error: VRAM bank 1 can't be used with option -w. diff --git a/test/link/vram-floating-dmg-mode-w.out b/test/link/vram-floating-dmg-mode-w.out index 31ad1d17..4367a910 100644 --- a/test/link/vram-floating-dmg-mode-w.out +++ b/test/link/vram-floating-dmg-mode-w.out @@ -1 +1 @@ -rgblink: error: Unable to place 'v1' (VRAM section) in any bank +error: Unable to place 'v1' (VRAM section) in any bank diff --git a/test/link/wramx-dmg-mode-no-w.out b/test/link/wramx-dmg-mode-no-w.out index 8f5a6dd3..dab00306 100644 --- a/test/link/wramx-dmg-mode-no-w.out +++ b/test/link/wramx-dmg-mode-no-w.out @@ -1 +1 @@ -rgblink: error: Unable to place 'w0b' (WRAM0 section) anywhere +error: Unable to place 'w0b' (WRAM0 section) anywhere diff --git a/test/link/wramx-dmg-mode-w.out b/test/link/wramx-dmg-mode-w.out index 4317b2d4..8ca11a50 100644 --- a/test/link/wramx-dmg-mode-w.out +++ b/test/link/wramx-dmg-mode-w.out @@ -1 +1 @@ -rgblink: error: WRAMX sections can't be used with option -w. +error: WRAMX sections can't be used with option -w. From 206275df57a65d6aeabaac9a0a4cb102eb333407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Ni=C3=B1o=20D=C3=ADaz?= Date: Sat, 8 Apr 2017 18:10:24 +0100 Subject: [PATCH 2/2] Add support for including files in linkerscript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Files can now be included with the following syntax: INCLUDE "path.link" The maximum include depth is 5. Fixed linkerscript parser and lexer error messages so that they are more informative (show file and line of the error). Man page updated. Signed-off-by: Antonio Niño Díaz --- include/link/script.h | 8 ++++ src/link/assign.c | 1 + src/link/lexer.l | 108 ++++++++++++++++++++++++++++++++++++++++-- src/link/parser.y | 52 +++++++++----------- src/link/rgblink.5 | 33 ++++++++----- 5 files changed, 156 insertions(+), 46 deletions(-) diff --git a/include/link/script.h b/include/link/script.h index 4e897cda..85b05144 100644 --- a/include/link/script.h +++ b/include/link/script.h @@ -17,8 +17,16 @@ #ifndef RGBDS_LINK_SCRIPT_H #define RGBDS_LINK_SCRIPT_H +#include "extern/stdnoreturn.h" + +noreturn void script_fatalerror(const char *fmt, ...); + void script_Parse(const char *path); +void script_IncludeFile(const char *path); +int script_IncludeDepthGet(void); +void script_IncludePop(void); + void script_InitSections(void); void script_SetCurrentSectionType(const char *type, unsigned int bank); void script_SetAddress(unsigned int addr); diff --git a/src/link/assign.c b/src/link/assign.c index e05cbadb..a2629c89 100644 --- a/src/link/assign.c +++ b/src/link/assign.c @@ -445,6 +445,7 @@ AssignSections(void) */ if (tzLinkerscriptName) { + script_InitSections(); script_Parse(tzLinkerscriptName); } diff --git a/src/link/lexer.l b/src/link/lexer.l index 1d36a293..afbfb4a3 100644 --- a/src/link/lexer.l +++ b/src/link/lexer.l @@ -16,22 +16,38 @@ %option noinput %option nounput +%option yylineno %{ +#include #include #include "extern/err.h" +#include "link/mylink.h" +#include "link/script.h" #include "parser.h" + +/* File include stack. */ + +#define MAX_INCLUDE_DEPTH 8 + +static int include_stack_ptr = 0; + +static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; +static char include_path[MAX_INCLUDE_DEPTH][_MAX_PATH + 1]; +static int include_line[MAX_INCLUDE_DEPTH]; + +static char linkerscript_path[_MAX_PATH + 1]; /* Base file */ %} %% \"([^\\\"]|\\.)*\" { if (strlen(yytext) > sizeof(yylval.s) - 1) - errx(1, "String is too long: \"%s\"\n.", yytext); + script_fatalerror("String is too long: %s\n.", yytext); if (strlen(yytext) < 3) /* 2 quotes + 1 character */ - errx(1, "String \"%s\" is invalid\n.", yytext); + script_fatalerror("String %s is invalid\n.", yytext); yytext++; /* ignore first quote */ strcpy(yylval.s, yytext); @@ -62,13 +78,99 @@ (?i:ALIGN) { return COMMAND_ALIGN; } (?i:ORG) { return COMMAND_ORG; } +(?i:INCLUDE) { return COMMAND_INCLUDE; } + "\n" { return NEWLINE; } ;.* { /* Ignore comments. A dot doesn't match newline. */ } [[:space:]] { /* Ignore whitespace. */ } -. { errx(1, "Invalid character [%s]\n.", yytext); } +. { script_fatalerror("Invalid character [%s]\n.", yytext); } %% +extern FILE *yyin; + +void script_Parse(const char * path) +{ + yyin = fopen(path, "r"); + + if (!yyin) + errx(1, "Error opening file! \"%s\"\n", path); + + strncpy(linkerscript_path, path, sizeof(linkerscript_path)); + linkerscript_path[sizeof(linkerscript_path) - 1] = '\0'; + + do { + yyparse(); + } while (!feof(yyin)); + + fclose(yyin); + +} + +void script_IncludeFile(const char * path) +{ + if (include_stack_ptr == (MAX_INCLUDE_DEPTH-1)) + script_fatalerror("Includes nested too deeply."); + + include_line[include_stack_ptr] = yylineno; + include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; + + include_stack_ptr++; + + yyin = fopen(path, "r" ); + + if (!yyin) + script_fatalerror("Couldn't open file \"%s\"", path); + + strncpy(include_path[include_stack_ptr], path, sizeof(include_path[0])); + include_path[include_stack_ptr][sizeof(include_path[0])-1] = '\0'; + + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + yylineno = 0; +} + +int script_IncludeDepthGet(void) +{ + return include_stack_ptr; +} + +void script_IncludePop(void) +{ + fclose(yyin); + + include_stack_ptr--; + + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(include_stack[include_stack_ptr]); + yylineno = include_line[include_stack_ptr]; +} + +void script_PrintFileStack(void) +{ + int i = include_stack_ptr; + + include_line[i] = yylineno; + + while (i > 0) { + fprintf(stderr, "%s(%d) -> ", include_path[i], include_line[i]); + i--; + } + fprintf(stderr, "%s(%d)", linkerscript_path, include_line[i]); +} + +noreturn void script_fatalerror(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + fprintf(stderr, "error: "); + script_PrintFileStack(); + fprintf(stderr, ":\n\t"); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + exit(1); +} + diff --git a/src/link/parser.y b/src/link/parser.y index 6fc4e54a..ce89deb5 100644 --- a/src/link/parser.y +++ b/src/link/parser.y @@ -23,7 +23,7 @@ int yylex(); void yyerror(char *); -static int nline = 1; +extern int yylineno; %} %union { int i; char s[512]; } @@ -37,6 +37,8 @@ static int nline = 1; %token COMMAND_ALIGN %token COMMAND_ORG +%token COMMAND_INCLUDE + %token NEWLINE %start lines @@ -49,8 +51,8 @@ lines: ; line: - /* empty */ { nline++; } - | statement { nline++; } + /* empty */ + | statement ; statement: @@ -59,11 +61,11 @@ statement: script_SetCurrentSectionType($1, 0); } | SECTION_NONBANKED INTEGER { - errx(1, "%d:Trying to assign a bank to a non-banked section.\n", nline); + script_fatalerror("Trying to assign a bank to a non-banked section.\n"); } | SECTION_BANKED { - errx(1, "%d:Banked section without assigned bank.\n", nline); + script_fatalerror("Banked section without assigned bank.\n"); } | SECTION_BANKED INTEGER { script_SetCurrentSectionType($1, $2); @@ -74,13 +76,13 @@ statement: script_SetAlignment($2); } | COMMAND_ALIGN { - errx(1, "%d:ALIGN keyword needs an argument.\n", nline); + script_fatalerror("ALIGN keyword needs an argument.\n"); } | COMMAND_ORG INTEGER { script_SetAddress($2); } | COMMAND_ORG { - errx(1, "%d:ORG keyword needs an argument.\n", nline); + script_fatalerror("ORG keyword needs an argument.\n"); } /* Section name */ @@ -88,6 +90,11 @@ statement: script_OutputSection($1); } + /* Include file */ + | COMMAND_INCLUDE STRING { + script_IncludeFile($2); + } + /* End */ ; @@ -96,33 +103,18 @@ statement: extern int yylex(); extern int yyparse(); -extern FILE *yyin; - -int yywrap (void) +int yywrap(void) { - return 1; + if (script_IncludeDepthGet() == 0) + return 1; + + script_IncludePop(); + + return 0; } void yyerror(char *s) { - errx(1, "%d:Linkerscript parse error: \"%s\"\n", nline, s); -} - -void script_Parse(const char *path) -{ - script_InitSections(); - - FILE *f = fopen(path, "r"); - - if (!f) - errx(1, "Error opening file! \"%s\"\n", path); - - yyin = f; - - do { - yyparse(); - } while (!feof(yyin)); - - fclose(f); + script_fatalerror("Linkerscript parse error: \"%s\"\n", s); } diff --git a/src/link/rgblink.5 b/src/link/rgblink.5 index 7a6c431f..1f88330f 100644 --- a/src/link/rgblink.5 +++ b/src/link/rgblink.5 @@ -12,7 +12,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd March 27, 2017 +.Dd April 8, 2017 .Dt RGBLINK 5 .Os RGBDS Manual .Sh NAME @@ -34,35 +34,42 @@ Any line can contain a comment starting with that ends at the end of the line: .Pp ROMX $F ; This is a comment - "Functions to read array" - ALIGN 8 - "Array aligned to 256 bytes" + "Functions to read array" + ALIGN 8 + "Array aligned to 256 bytes" WRAMX 2 - "Some variables" + "Some variables" .Pp Numbers can be in decimal or hexadecimal format (the prefix is .Ql $ ) . It is an error if any bank or command is found before setting a bank. .Pp -The possible bank types are: ROM0, ROMX, VRAM, WRAM0, WRAMX, OAM and HRAM. -Types ROMX, VRAM, WRAMX and SRAM are banked, which means that it is needed to -specify a bank after the type. +Files can be included by using the +.Ar INCLUDE No keyword followed by a string with the path of the file that has +to be included. +.Pp +The possible bank types are: +.Sy ROM0 , ROMX , VRAM , WRAM0 , WRAMX , OAM No and Sy HRAM . +Types +.Sy ROMX , VRAM , WRAMX No and Sy SRAM No are banked, which means that it is +needed to specify a bank after the type. .Pp When a new bank statement is found, sections found after it will be placed right from the beginning of that bank. If the linkerscript switches to a different bank and then it comes back to the previous one it will continue from the last address that was used. .Pp -The only two commands are ORG and ALIGN: +The only two commands are +.Ar ORG No and Ar ALIGN : .Bl -bullet .It -ORG sets the address in which new sections will be placed. +.Ar ORG No sets the address in which new sections will be placed. It can not be lower than the current address. .It -ALIGN will increase the address until it is aligned to the specified boundary -(it tries to set to 0 the number of bits specified after the command: ALIGN 8 -will align to $100). +.Ar ALIGN No will increase the address until it is aligned to the specified +boundary (it tries to set to 0 the number of bits specified after the command: +.Ar ALIGN No 8 No will align to No $100 ) . .El .Pp Note: The bank, alignment, address and type of sections can be specified both