#include "asmmon.h"
#include "cpu/sux/cpu.h"
#include "lexer.h"
int isidstart(char c) {
return (isalpha(c) || c == '@' || c == '_');
}
int isidchar(char c) {
return (isalnum(c) || c == '_');
}
char *skip(char *s) {
for (; isspace(*s); s++);
return s;
}
int iseol(char c) {
return (c == '\0' || c == ';');
}
void eol(char *s) {
if (ignore_trail) {
if (!iseol(*s) && !isspace(*s)) {
syntax_error(6);
}
} else {
s = skip(s);
if (!iseol(*s)) {
syntax_error(6);
}
}
}
int isbadid(char *p, int len) {
return (len == 1 && (*p == '@' || *p == '_'));
}
char *skip_operand(int inst_op, char *s) {
int brack_count = 0;
int done = 0;
for (char c = 0;; s++) {
c = *s;
switch (c) {
case '(': brack_count++; break;
case ')':
if (brack_count > 0) {
brack_count--;
} else {
syntax_error(3);
}
break;
case '\'':
case '\"': s = skip_string(s, c, NULL) - 1; break;
case '\0':
case ';' : done = 1; break;
default :
if ((!inst_op || (inst_op && OPERSEP_COMMA)) && c == ',' && !brack_count) {
done = 1;
break;
} else if (inst_op && OPERSEP_WHITESPACE && isspace(c) && !brack_count) {
done = 1;
break;
}
break;
}
if (done) {
break;
}
}
if (brack_count) {
syntax_error(4);
}
return s;
}
char *skip_local(char *p) {
if (isidstart(*p) || isdigit(*p)) {
for (p++; isidchar(*p); p++);
} else {
p = NULL;
}
return p;
}
char *get_local_label(char **start) {
char *s = *start;
char *p = skip_local(s);
char *name = NULL;
if (p != NULL && *p == '@' && isidchar(p[1]) && isidstart(*s) && *s != '@') {
s = p+1;
p = skip_local(p);
name = make_local_label(*start, (s-1) - *start, s, p-s);
*start = skip(p);
} else if (p != NULL && p > s+1 && *s == '@') {
s++;
name = make_local_label(NULL, 0, s, p-s);
*start = skip(p);
}
return name;
}
char *parse_label_or_pc(char **start) {
char *s = skip(*start);
char *name = parse_labeldef(start, 0);
if (name == NULL && *s == current_pc_char && !isidchar(s[1])) {
name = cnvstr(s, 1);
s = skip(s+1);
}
*start = (name) ? s : *start;
return name;
}
uint64_t lex(char *line, uint64_t address, uint16_t bline, uint8_t dbg) {
char *s;
char *inst;
char *label_name;
char *ext[MAX_QUALIFIERS ? MAX_QUALIFIERS : 1];
char *op[MAX_OPERANDS];
int ext_len[MAX_QUALIFIERS ? MAX_QUALIFIERS : 1];
int op_len[MAX_OPERANDS];
int ext_cnt;
int op_cnt;
int inst_len;
s = line;
instruction *ip;
while (isdelm(*s, dbg) != 1) {
label_name = parse_label_or_pc(&s);
if (label_name) {
symbol *label;
int equ_len = (*s == '=');
if (equ_len) {
if (*label_name == current_pc_char) {
handle_org(skip(s+equ_len));
continue;
} else {
s = skip(s+equ_len);
label = new_equate(label_name, parse_expr_tmplab(&s));
}
} else {
label = new_label_sym(0, label_name);
add_atom(0, new_label_atom(label));
}
if (!is_local_label(label_name) && autoexport) {
label->flags |= EXPORT;
}
free(label_name);
}
s = skip(s);
if (*s == ';') {
continue;
}
if (*s == current_pc_char && s[1] == '=') {
handle_org(skip(s+2));
continue;
}
if (handle_directive(s)) {
continue;
}
s = skip(s);
if (iseol(s)) {
continue;
}
inst = s;
if (!isidstart(*s)) {
syntax_error(10);
continue;
}
#if !MAX_QUALLIFIERS
for (; *s && !isspace(*s); s++);
inst_len = s - inst;
#else
s = lex_inst(s, &inst_len, ext, ext_len, &ext_cnt);
#endif
if (!isspace(*s) && *s != '\0') {
syntax_error(2);
}
s = skip(s);
if (handle_struct(inst, inst_len, s)) {
continue;
}
op_cnt = 0;
while (!iseol(*s) && op_cnt < MAX_OPERANDS) {
op[op_cnt] = s;
s = skip_operand(1, s);
op_len[op_cnt] = oplen(s, op[op_cnt]);
op_cnt++;
if (ignore_trail) {
if (*s != ',') {
break;
}
s++;
} else {
s = skip(s);
if (OPERSEP_COMMA) {
if (*s == ',') {
s = skip(s+1);
} else if (!(OPERSEP_WHITESPACE)) {
break;
}
}
}
}
eol(s);
ip = new_inst(inst, inst_len, op_cnt, op, op_len);
if (ip) {
#if MAX_QUALIFIERS > 0
int i;
for (i = 0; i < ext_cnt; i++) {
ip->qualifiers[i] = cnvstr(ext[i], ext_len[i]);
}
for (; i < MAX_QUALIFIERS; i++) {
ip->qualifiers[i] = NULL;
}
#endif
add_atom(0, new_inst_atom(ip));
}
}
}