shithub: rgbds

Download patch

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.