ref: fa767f32285abf9d7c840514e64ff99adaaab178
parent: 23584a584f44af28aea5943341e5344f45d88b8a
parent: 206275df57a65d6aeabaac9a0a4cb102eb333407
author: Antonio Niño Díaz <[email protected]>
date: Sun Apr 9 13:19:13 EDT 2017
Merge pull request #161 from AntonioND/an/linkerscript-include Add support for including files in linkerscript Signed-off-by: Antonio Niño Díaz <[email protected]>
--- a/include/link/script.h
+++ b/include/link/script.h
@@ -17,7 +17,15 @@
#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);
--- a/src/asm/main.c
+++ b/src/asm/main.c
@@ -20,8 +20,6 @@
int cldefines_size;
char **cldefines;
-char *progname;
-
clock_t nStartClock, nEndClock;
SLONG nLineNo;
ULONG nTotalLines, nPass, nPC, nIFDepth, nErrors;
@@ -300,8 +298,6 @@
if (argc == 1)
usage();
-
- progname = "rgbasm";
/* yydebug=1; */
--- a/src/extern/err.c
+++ b/src/extern/err.c
@@ -26,11 +26,9 @@
#include <stdlib.h>
#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_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 @@
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_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);
--- a/src/fix/main.c
+++ b/src/fix/main.c
@@ -23,8 +23,6 @@
#include "extern/err.h"
-char *progname;
-
static void
usage(void)
{
@@ -70,8 +68,6 @@
int ramsize; /* RAM size ID */
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) {
--- a/src/gfx/main.c
+++ b/src/gfx/main.c
@@ -19,8 +19,6 @@
#include <string.h>
#include "gfx/main.h"
-char *progname;
-
static void
usage(void)
{
@@ -40,8 +38,6 @@
struct Tilemap tilemap = {0};
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();
--- a/src/link/assign.c
+++ b/src/link/assign.c
@@ -445,6 +445,7 @@
*/
if (tzLinkerscriptName) {
+ script_InitSections();
script_Parse(tzLinkerscriptName);
}
--- a/src/link/lexer.l
+++ b/src/link/lexer.l
@@ -16,13 +16,29 @@
%option noinput
%option nounput
+%option yylineno
%{
+#include <stdarg.h>
#include <unistd.h>
#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 */
%}
%%
@@ -29,9 +45,9 @@
\"([^\\\"]|\\.)*\" {
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,6 +78,8 @@
(?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. */ }
@@ -68,7 +86,91 @@
[[: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);
+}
--- a/src/link/main.c
+++ b/src/link/main.c
@@ -24,8 +24,6 @@
SLONG fillchar = 0;
char *smartlinkstartsymbol;
-char *progname;
-
/*
* Print the usagescreen
*
@@ -53,8 +51,6 @@
if (argc == 1)
usage();
-
- progname = "rgblink";
while ((ch = getopt(argc, argv, "l:m:n:o:O:p:s:tw")) != -1) {
switch (ch) {
--- 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 @@
%token COMMAND_ALIGN
%token COMMAND_ORG
+%token COMMAND_INCLUDE
+
%token NEWLINE
%start lines
@@ -49,8 +51,8 @@
;
line:
- /* empty */ { nline++; }
- | statement { nline++; }
+ /* empty */
+ | statement
;
statement:
@@ -59,11 +61,11 @@
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 @@
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 @@
script_OutputSection($1);
}
+ /* Include file */
+ | COMMAND_INCLUDE STRING {
+ script_IncludeFile($2);
+ }
+
/* End */
;
@@ -96,33 +103,18 @@
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);
}
--- 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 @@
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
--- 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)!
--- a/test/link/romx-tiny-no-t.out
+++ b/test/link/romx-tiny-no-t.out
@@ -1,1 +1,1 @@
-rgblink: error: Unable to place 'r0b' (ROM0 section) anywhere
+error: Unable to place 'r0b' (ROM0 section) anywhere
--- a/test/link/romx-tiny-t.out
+++ b/test/link/romx-tiny-t.out
@@ -1,1 +1,1 @@
-rgblink: error: ROMX sections can't be used with option -t.
+error: ROMX sections can't be used with option -t.
--- a/test/link/vram-fixed-dmg-mode-w.out
+++ b/test/link/vram-fixed-dmg-mode-w.out
@@ -1,1 +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.
--- a/test/link/vram-floating-dmg-mode-w.out
+++ b/test/link/vram-floating-dmg-mode-w.out
@@ -1,1 +1,1 @@
-rgblink: error: Unable to place 'v1' (VRAM section) in any bank
+error: Unable to place 'v1' (VRAM section) in any bank
--- a/test/link/wramx-dmg-mode-no-w.out
+++ b/test/link/wramx-dmg-mode-no-w.out
@@ -1,1 +1,1 @@
-rgblink: error: Unable to place 'w0b' (WRAM0 section) anywhere
+error: Unable to place 'w0b' (WRAM0 section) anywhere
--- a/test/link/wramx-dmg-mode-w.out
+++ b/test/link/wramx-dmg-mode-w.out
@@ -1,1 +1,1 @@
-rgblink: error: WRAMX sections can't be used with option -w.
+error: WRAMX sections can't be used with option -w.