(uxnasm) Preserve line context across includes
This commit is contained in:
parent
56131efa43
commit
af87818228
85
src/uxnasm.c
85
src/uxnasm.c
|
@ -22,7 +22,7 @@ typedef struct {
|
||||||
Uint16 addr, refs;
|
Uint16 addr, refs;
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
static int ptr, length, line;
|
static int ptr, length;
|
||||||
static char source[0x40], token[0x40], scope[0x40], sublabel[0x80], lambda[0x05];
|
static char source[0x40], token[0x40], scope[0x40], sublabel[0x80], lambda[0x05];
|
||||||
static char dict[0x10000], *dictnext = dict;
|
static char dict[0x10000], *dictnext = dict;
|
||||||
static Uint8 data[0x10000], lambda_stack[0x100], lambda_ptr, lambda_len;
|
static Uint8 data[0x10000], lambda_stack[0x100], lambda_ptr, lambda_len;
|
||||||
|
@ -50,16 +50,16 @@ static char *scat(char *dst, char *src) { char *o = dst + slen(dst); while(*src)
|
||||||
static char *push(char *s, char c) { char *o = dictnext; while((*dictnext++ = *s++) && *s); *dictnext++ = c; return o; } /* save str */
|
static char *push(char *s, char c) { char *o = dictnext; while((*dictnext++ = *s++) && *s); *dictnext++ = c; return o; } /* save str */
|
||||||
|
|
||||||
#define isopcode(x) (findopcode(x) || scmp(x, "BRK", 4))
|
#define isopcode(x) (findopcode(x) || scmp(x, "BRK", 4))
|
||||||
#define writeshort(x) (writebyte(x >> 8) && writebyte(x & 0xff))
|
#define writeshort(x) (writebyte(x >> 8, ln) && writebyte(x & 0xff, ln))
|
||||||
#define makesublabel(x) push(scat(scat(scpy(scope, sublabel, 0x40), "/"), x), 0)
|
#define makesublabel(x) push(scat(scat(scpy(scope, sublabel, 0x40), "/"), x), 0)
|
||||||
#define findlabel(x) finditem(x, labels, label_len)
|
#define findlabel(x) finditem(x, labels, label_len)
|
||||||
#define findmacro(x) finditem(x, macros, macro_len)
|
#define findmacro(x) finditem(x, macros, macro_len)
|
||||||
#define error_top(name, msg) !!fprintf(stderr, "%s: %s\n", name, msg)
|
#define error_top(name, msg) !!fprintf(stderr, "%s: %s\n", name, msg)
|
||||||
#define error_asm(name) !!fprintf(stderr, "%s: %s in @%s, %s:%d.\n", name, token, scope, source, line)
|
#define error_asm(name) !!fprintf(stderr, "%s: %s in @%s, %s:%d.\n", name, token, scope, source, ln)
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
static int parse(char *w, FILE *f);
|
static int parse(char *w, FILE *f, int *ln);
|
||||||
|
|
||||||
static Item *
|
static Item *
|
||||||
finditem(char *name, Item *list, int len)
|
finditem(char *name, Item *list, int len)
|
||||||
|
@ -100,12 +100,12 @@ findopcode(char *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
walkcomment(FILE *f)
|
walkcomment(FILE *f, int *ln)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
int depth = 1;
|
int depth = 1;
|
||||||
while(f && fread(&c, 1, 1, f)) {
|
while(f && fread(&c, 1, 1, f)) {
|
||||||
if(c == 0xa) line++;
|
if(c == 0xa) ln++;
|
||||||
if(c == '(') depth++;
|
if(c == '(') depth++;
|
||||||
if(c == ')' && --depth < 1) return 1;
|
if(c == ')' && --depth < 1) return 1;
|
||||||
}
|
}
|
||||||
|
@ -113,13 +113,13 @@ walkcomment(FILE *f)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
walkmacro(Item *m)
|
walkmacro(Item *m, int *ln)
|
||||||
{
|
{
|
||||||
char c, *contentptr = m->content, *cptr = token;
|
char c, *contentptr = m->content, *cptr = token;
|
||||||
while((c = *contentptr++)) {
|
while((c = *contentptr++)) {
|
||||||
if(c < 0x21) {
|
if(c < 0x21) {
|
||||||
*cptr++ = 0x00;
|
*cptr++ = 0x00;
|
||||||
if(token[0] && !parse(token, NULL)) return 0;
|
if(token[0] && !parse(token, NULL, ln)) return 0;
|
||||||
cptr = token;
|
cptr = token;
|
||||||
} else
|
} else
|
||||||
*cptr++ = c;
|
*cptr++ = c;
|
||||||
|
@ -128,14 +128,14 @@ walkmacro(Item *m)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
walkfile(FILE *f)
|
walkfile(FILE *f, int *ln)
|
||||||
{
|
{
|
||||||
char c, *cptr = token;
|
char c, *cptr = token;
|
||||||
while(f && fread(&c, 1, 1, f)) {
|
while(f && fread(&c, 1, 1, f)) {
|
||||||
if(c == 0xa) line++;
|
if(c == 0xa) *ln++;
|
||||||
if(c < 0x21) {
|
if(c < 0x21) {
|
||||||
*cptr++ = 0x00;
|
*cptr++ = 0x00;
|
||||||
if(token[0] && !parse(token, f))
|
if(token[0] && !parse(token, f, ln))
|
||||||
return 0;
|
return 0;
|
||||||
cptr = token;
|
cptr = token;
|
||||||
} else if(cptr - token < 0x3f)
|
} else if(cptr - token < 0x3f)
|
||||||
|
@ -147,7 +147,7 @@ walkfile(FILE *f)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
makemacro(char *name, FILE *f)
|
makemacro(char *name, FILE *f, int *ln)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
Item *m;
|
Item *m;
|
||||||
|
@ -160,11 +160,11 @@ makemacro(char *name, FILE *f)
|
||||||
m->name = push(name, 0);
|
m->name = push(name, 0);
|
||||||
m->content = dictnext;
|
m->content = dictnext;
|
||||||
while(f && fread(&c, 1, 1, f) && c != '{')
|
while(f && fread(&c, 1, 1, f) && c != '{')
|
||||||
if(c == 0xa) line++;
|
if(c == 0xa) ln++;
|
||||||
while(f && fread(&c, 1, 1, f) && c != '}') {
|
while(f && fread(&c, 1, 1, f) && c != '}') {
|
||||||
if(c == 0xa) line++;
|
if(c == 0xa) ln++;
|
||||||
if(c == '%') return 0;
|
if(c == '%') return 0;
|
||||||
if(c == '(') walkcomment(f);
|
if(c == '(') walkcomment(f, ln);
|
||||||
*dictnext++ = c;
|
*dictnext++ = c;
|
||||||
}
|
}
|
||||||
*dictnext++ = 0;
|
*dictnext++ = 0;
|
||||||
|
@ -172,7 +172,7 @@ makemacro(char *name, FILE *f)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
makelabel(char *name, int setscope)
|
makelabel(char *name, int setscope, int *ln)
|
||||||
{
|
{
|
||||||
Item *l;
|
Item *l;
|
||||||
if(name[0] == '&')
|
if(name[0] == '&')
|
||||||
|
@ -222,7 +222,7 @@ addref(char *label, char rune, Uint16 addr)
|
||||||
{
|
{
|
||||||
Item *r;
|
Item *r;
|
||||||
if(refs_len >= 0x1000)
|
if(refs_len >= 0x1000)
|
||||||
return error_asm("References limit exceeded");
|
return error_top("References limit exceeded", label);
|
||||||
r = &refs[refs_len++];
|
r = &refs[refs_len++];
|
||||||
if(label[0] == '{') {
|
if(label[0] == '{') {
|
||||||
lambda_stack[lambda_ptr++] = lambda_len;
|
lambda_stack[lambda_ptr++] = lambda_len;
|
||||||
|
@ -237,7 +237,7 @@ addref(char *label, char rune, Uint16 addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
writebyte(Uint8 b)
|
writebyte(Uint8 b, int *ln)
|
||||||
{
|
{
|
||||||
if(ptr < PAGE)
|
if(ptr < PAGE)
|
||||||
return error_asm("Writing in zero-page");
|
return error_asm("Writing in zero-page");
|
||||||
|
@ -251,12 +251,12 @@ writebyte(Uint8 b)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
writehex(char *w)
|
writehex(char *w, int *ln)
|
||||||
{
|
{
|
||||||
if(*w == '#')
|
if(*w == '#')
|
||||||
writebyte(findopcode("LIT") | (slen(++w) > 2) << 5);
|
writebyte(findopcode("LIT") | (slen(++w) > 2) << 5, ln);
|
||||||
if(slen(w) == 2)
|
if(slen(w) == 2)
|
||||||
return writebyte(shex(w));
|
return writebyte(shex(w), ln);
|
||||||
else if(slen(w) == 4)
|
else if(slen(w) == 4)
|
||||||
return writeshort(shex(w));
|
return writeshort(shex(w));
|
||||||
else
|
else
|
||||||
|
@ -267,38 +267,37 @@ static int
|
||||||
makeinclude(char *filename)
|
makeinclude(char *filename)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int res = 0;
|
int res = 0, ln = 0;
|
||||||
if(!(f = fopen(filename, "r")))
|
if(!(f = fopen(filename, "r")))
|
||||||
return error_top("Invalid source", filename);
|
return error_top("Invalid source", filename);
|
||||||
scpy(filename, source, 0x40);
|
scpy(filename, source, 0x40);
|
||||||
line = 0;
|
res = walkfile(f, &ln);
|
||||||
res = walkfile(f);
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse(char *w, FILE *f)
|
parse(char *w, FILE *f, int *ln)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
Item *m;
|
Item *m;
|
||||||
switch(w[0]) {
|
switch(w[0]) {
|
||||||
case '(': return !walkcomment(f) ? error_asm("Invalid comment") : 1;
|
case '(': return !walkcomment(f, ln) ? error_asm("Invalid comment") : 1;
|
||||||
case '~': return !makeinclude(w + 1) ? error_asm("Invalid include") : 1;
|
case '~': return !makeinclude(w + 1) ? error_asm("Invalid include") : 1;
|
||||||
case '%': return !makemacro(w + 1, f) ? error_asm("Invalid macro") : 1;
|
case '%': return !makemacro(w + 1, f, ln) ? error_asm("Invalid macro") : 1;
|
||||||
case '@': return !makelabel(w + 1, 1) ? error_asm("Invalid label") : 1;
|
case '@': return !makelabel(w + 1, 1, ln) ? error_asm("Invalid label") : 1;
|
||||||
case '&': return !makelabel(w, 0) ? error_asm("Invalid sublabel") : 1;
|
case '&': return !makelabel(w, 0, ln) ? error_asm("Invalid sublabel") : 1;
|
||||||
case '#': return !sihx(w + 1) || !writehex(w) ? error_asm("Invalid hexadecimal") : 1;
|
case '#': return !sihx(w + 1) || !writehex(w, ln) ? error_asm("Invalid hexadecimal") : 1;
|
||||||
case '_': return addref(w + 1, w[0], ptr) && writebyte(0xff);
|
case '_': return addref(w + 1, w[0], ptr) && writebyte(0xff, ln);
|
||||||
case ',': return addref(w + 1, w[0], ptr + 1) && writebyte(findopcode("LIT")) && writebyte(0xff);
|
case ',': return addref(w + 1, w[0], ptr + 1) && writebyte(findopcode("LIT"), ln) && writebyte(0xff, ln);
|
||||||
case '-': return addref(w + 1, w[0], ptr) && writebyte(0xff);
|
case '-': return addref(w + 1, w[0], ptr) && writebyte(0xff, ln);
|
||||||
case '.': return addref(w + 1, w[0], ptr + 1) && writebyte(findopcode("LIT")) && writebyte(0xff);
|
case '.': return addref(w + 1, w[0], ptr + 1) && writebyte(findopcode("LIT"), ln) && writebyte(0xff, ln);
|
||||||
case ':': fprintf(stderr, "Deprecated rune %s, use =%s\n", w, w + 1); /* fall-through */
|
case ':': fprintf(stderr, "Deprecated rune %s, use =%s\n", w, w + 1); /* fall-through */
|
||||||
case '=': return addref(w + 1, w[0], ptr) && writeshort(0xffff);
|
case '=': return addref(w + 1, w[0], ptr) && writeshort(0xffff);
|
||||||
case ';': return addref(w + 1, w[0], ptr + 1) && writebyte(findopcode("LIT2")) && writeshort(0xffff);
|
case ';': return addref(w + 1, w[0], ptr + 1) && writebyte(findopcode("LIT2"), ln) && writeshort(0xffff);
|
||||||
case '?': return addref(w + 1, w[0], ptr + 1) && writebyte(0x20) && writeshort(0xffff);
|
case '?': return addref(w + 1, w[0], ptr + 1) && writebyte(0x20, ln) && writeshort(0xffff);
|
||||||
case '!': return addref(w + 1, w[0], ptr + 1) && writebyte(0x40) && writeshort(0xffff);
|
case '!': return addref(w + 1, w[0], ptr + 1) && writebyte(0x40, ln) && writeshort(0xffff);
|
||||||
case '}': return !makelabel(makelambda(lambda_stack[--lambda_ptr]), 0) ? error_asm("Invalid label") : 1;
|
case '}': return !makelabel(makelambda(lambda_stack[--lambda_ptr]), 0, ln) ? error_asm("Invalid label") : 1;
|
||||||
case '$':
|
case '$':
|
||||||
case '|': return !makepad(w) ? error_asm("Invalid padding") : 1;
|
case '|': return !makepad(w) ? error_asm("Invalid padding") : 1;
|
||||||
case '[':
|
case '[':
|
||||||
|
@ -306,17 +305,17 @@ parse(char *w, FILE *f)
|
||||||
if(slen(w) == 1) break; /* else fallthrough */
|
if(slen(w) == 1) break; /* else fallthrough */
|
||||||
case '"': /* raw string */
|
case '"': /* raw string */
|
||||||
while((c = *(++w)))
|
while((c = *(++w)))
|
||||||
if(!writebyte(c)) return 0;
|
if(!writebyte(c, ln)) return 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if(sihx(w))
|
if(sihx(w))
|
||||||
return writehex(w);
|
return writehex(w, ln);
|
||||||
else if(isopcode(w))
|
else if(isopcode(w))
|
||||||
return writebyte(findopcode(w));
|
return writebyte(findopcode(w), ln);
|
||||||
else if((m = findmacro(w)))
|
else if((m = findmacro(w)))
|
||||||
return walkmacro(m);
|
return walkmacro(m, ln);
|
||||||
else
|
else
|
||||||
return addref(w, ' ', ptr + 1) && writebyte(0x60) && writeshort(0xffff);
|
return addref(w, ' ', ptr + 1) && writebyte(0x60, ln) && writeshort(0xffff);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue