ref: 395a3c572792c6270427954ff55b76c6d976a479
parent: 60c8089ebc884a96d6a89c7388c579973d3e59fd
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Thu Feb 1 14:57:54 EST 2018
[as] Add support for recursive inclusion
--- a/as/as.h
+++ b/as/as.h
@@ -176,6 +176,8 @@
extern void regctx(int mode);
extern Node *getreg(void);
extern Node *operand(char **s);
+extern void addinput(char *fname);
+extern int delinput(void);
/* expr.c */
extern Node *expr(void);
--- a/as/expr.c
+++ b/as/expr.c
@@ -164,20 +164,14 @@
static Node *
primary(void)
{
- int addr, op;
Node *np;
switch (yytoken) {
case IDEN:
case NUMBER:
- addr = ANUMBER;
- goto basic_atom;
- case STRING:
- addr = ASTR;
- basic_atom:
np = node(yytoken, NULL, NULL);
np->sym = yylval.sym;
- np->addr = addr;
+ np->addr = ANUMBER;
next();
break;
case '(':
--- a/as/ins.c
+++ b/as/ins.c
@@ -241,3 +241,9 @@
{
endpass = 1;
}
+
+void
+include(Op *op, Node **args)
+{
+ addinput(args[0]->sym->name.buf);
+}
--- a/as/main.c
+++ b/as/main.c
@@ -74,8 +74,7 @@
extern int nerrors;
extern jmp_buf recover;
- if ((fp = fopen(fname, "r")) == NULL)
- die("as: error opening '%s'", fname);
+ addinput(fname);
cleansecs();
endpass = 0;
@@ -92,8 +91,6 @@
error("arguments without an opcode");
}
- if (fclose(fp))
- die("as: error reading from input file '%s'", fname);
return nerrors == 0;
}
--- a/as/parser.c
+++ b/as/parser.c
@@ -1,4 +1,5 @@
static char sccsid[] = "@(#) ./as/parser.c";
+#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <setjmp.h>
@@ -12,8 +13,15 @@
#include "as.h"
#define NARGS 20
+#define NR_INPUTS 10
#define MAXLINE 100
+struct input {
+ char *fname;
+ unsigned lineno;
+ FILE *fp;
+};
+
int nerrors;
jmp_buf recover;
char yytext[INTIDENTSIZ+1];
@@ -24,6 +32,7 @@
static char *textp, *endp;
static int regmode;
static unsigned lineno;
+static struct input inputs[NR_INPUTS], *isp = inputs;
static int
follow(int expect1, int expect2, int ifyes1, int ifyes2, int ifno)
@@ -121,15 +130,20 @@
string(void)
{
int c;
- char *p;
+ size_t l;
+ char *s;
+ Symbol *sym = tmpsym(0);
for (++endp; *endp != '"'; ++endp)
;
++endp;
tok2str();
- yylval.sym = tmpsym(0);
+ yylval.sym = sym;
/* FIXME: this memory is not freed ever */
- yylval.sym->name.buf = xstrdup(yytext);
+ l = yylen-2;
+ s = memcpy(xmalloc(l+1), yytext+1, l);
+ s[l] = '\0';
+ sym->name.buf = s;
return STRING;
}
@@ -207,9 +221,13 @@
error(char *msg, ...)
{
va_list va;
+ struct input *ip;
+ assert(isp > inputs);
+ ip = &isp[-1];
+
va_start(va, msg);
- fprintf(stderr, "as:%s:%u: ", infile, lineno);
+ fprintf(stderr, "as:%s:%u: ", ip->fname, ip->lineno);
vfprintf(stderr, msg, va);
putc('\n', stderr);
nerrors++;
@@ -253,6 +271,12 @@
case REG:
np = getreg();
break;
+ case STRING:
+ np = node(yytoken, NULL, NULL);
+ np->sym = yylval.sym;
+ np->addr = ASTR;
+ next();
+ break;
case '$':
next();
imm = 1;
@@ -403,17 +427,51 @@
int
nextline(FILE *fp, struct line *lp)
{
+ struct input *ip;
size_t n;
static char buff[MAXLINE];
+ assert(isp > inputs);
repeat:
- if (feof(fp))
+ if (isp == inputs)
return 0;
- if ((n = getline(fp, buff)) == 0)
+ ip = &isp[-1];
+ if (feof(ip->fp)) {
+ delinput();
goto repeat;
- if (++lineno == 0)
+ }
+ if ((n = getline(ip->fp, buff)) == 0)
+ goto repeat;
+ if (++ip->lineno == 0)
die("as: file too long");
if (extract(buff, n, lp) == 0)
goto repeat;
return 1;
+}
+
+void
+addinput(char *fname)
+{
+ FILE *fp;
+
+ if (isp == &inputs[NR_INPUTS])
+ die("too many included files");
+ if ((fp = fopen(fname, "r")) == NULL)
+ die("error opening input file '%s'", fname);
+ isp->fname = xstrdup(fname);
+ isp->fp = fp;
+ isp->lineno = 0;
+ ++isp;
+}
+
+int
+delinput(void)
+{
+ if (isp == inputs)
+ return EOF;
+ --isp;
+ if (fclose(isp->fp) == EOF)
+ die("error closing file '%s'", isp->fname);
+ free(isp->fname);
+ return 0;
}
--- a/as/target/x80/x80.dat
+++ b/as/target/x80/x80.dat
@@ -32,6 +32,7 @@
.ASCII string+ 0 none ascii Z80,R800,GB80
.ALIGN imm16+ 0 none align Z80,R800,GB80
.END none 0 none end Z80,R800,GB80
+.INCLUDE string 0 none include Z80,R800,GB80