1#include <assert.h>2#include <ctype.h>3#include <errno.h>4#include <limits.h>5#include <setjmp.h>6#include <stdarg.h>7#include <stdio.h>8#include <stdlib.h>9#include <string.h>1011#include <scc/cstd.h>12#include <scc/mach.h>13#include <scc/scc.h>1415#include "as.h"1617#define NARGS 2018#define NR_INPUTS 1019#define MAXLINE 1002021struct input {22 char *fname;23 unsigned lineno;24 FILE *fp;25};2627int nerrors;28jmp_buf recover;29char yytext[INTIDENTSIZ+1];30int yytoken;31size_t yylen;32union yylval yylval;3334static char *textp, *endp;35static int regmode;36static struct input inputs[NR_INPUTS], *isp = inputs;3738static int39follow(int expect1, int expect2, int ifyes1, int ifyes2, int ifno)40{41 int c;4243 if ((c = *++textp) == expect1)44 return ifyes1;45 if (c == expect2)46 return ifyes2;47 --textp;48 return ifno;49}5051static void52tok2str(void)53{54 if ((yylen = endp - textp) > INTIDENTSIZ) {55 error("token too big");56 yylen = INTIDENTSIZ;57 }58 memcpy(yytext, textp, yylen);59 yytext[yylen] = '\0';60 textp = endp;61}6263static int64iden(void)65{66 int c;67 char *p;6869 for ( ; c = *endp; ++endp) {70 if (isalnum(c))71 continue;72 switch (c) {73 case '\'':74 case '_':75 case '.':76 case '$':77 continue;78 default:79 goto out_loop;80 }81 }8283out_loop:84 tok2str();85 yylval.sym = lookup(yytext);8687 return (yylval.sym->flags & FREG) ? REG : IDEN;88}8990static int91number(void)92{93 int c, base = 10;94 char *p;95 unsigned long long n;96 static char digits[] = "0123456789ABCDEF";9798 if (*endp == '0') {99 base = 8;100 ++endp;101 if (*endp == 'x') {102 base = 16;103 ++endp;104 }105 }106 for (n = 0; (c = *endp) && isxdigit(c); n += c) {107 p = strchr(digits, toupper(c));108 c = p - digits;109 if (c > base)110 error("invalid digit in number");111 if (n >= ULLONG_MAX/base - c)112 error("overflow in number");113 n *= base;114 endp++;115 }116 tok2str();117 yylval.sym = tmpsym(n);118119 return NUMBER;120}121122static int123character(void)124{125 int c;126 char *p;127128 while (*endp != '\'')129 ++endp;130 return NUMBER;131}132133static int134string(void)135{136 int c;137 size_t l;138 char *s;139 Symbol *sym = tmpsym(0);140141 for (++endp; *endp != '"'; ++endp)142 ;143 ++endp;144 tok2str();145 yylval.sym = sym;146 /* FIXME: this memory is not freed ever */147 l = yylen-2;148 s = memcpy(xmalloc(l+1), yytext+1, l);149 s[l] = '\0';150 sym->name = s;151152 return STRING;153}154155static int156operator(void)157{158 int c;159160 ++endp;161 if ((c = *textp) == '>')162 c = follow('=', '>', LE, SHL, '>');163 else if (c == '<')164 c = follow('=', '<', GE, SHR, '>');165 tok2str();166167 return c;168}169170int171ahead(void)172{173 while (isspace(*textp))174 ++textp;175176 if (*textp != '\0')177 return *textp;178 return EOS;179}180181int182next(void)183{184 int c;185186 while (isspace(*textp))187 ++textp;188189 endp = textp;190191 switch (c = *textp) {192 case '\0':193 strcpy(yytext, "EOS");194 yylen = 3;195 c = EOS;196 break;197 case '"':198 c = string();199 break;200 case '\'':201 c = character();202 break;203 case '%':204 c = (regmode ? iden : operator)();205 break;206 case '.':207 case '_':208 c = iden();209 break;210 default:211 if (isdigit(c))212 c = number();213 else if (isalpha(c))214 c = iden();215 else216 c = operator();217 break;218 }219 return yytoken = c;220}221222void223expect(int token)224{225 if (yytoken != token)226 unexpected();227 next();228}229230void231unexpected(void)232{233 error("unexpected '%s'", yytext);234}235236void237error(char *msg, ...)238{239 va_list va;240 struct input *ip;241242 assert(isp > inputs);243 ip = &isp[-1];244245 va_start(va, msg);246 fprintf(stderr, "as:%s:%u: ", ip->fname, ip->lineno);247 vfprintf(stderr, msg, va);248 putc('\n', stderr);249 nerrors++;250 va_end(va);251252 if (nerrors == 10)253 die("as: too many errors");254 longjmp(recover, 1);255}256257Node *258getreg(void)259{260 Node *np;261262 np = node(REG, NULL, NULL);263 np->sym = yylval.sym;264 np->addr = AREG;265 expect(REG);266 return np;267}268269void270regctx(int mode)271{272 regmode = mode;273}274275Node *276operand(char **strp)277{278 int c, imm = 0;279 Node *np;280281 textp = *strp;282 regctx(1);283 switch (next()) {284 case EOS:285 np = NULL;286 break;287 case REG:288 np = getreg();289 break;290 case STRING:291 np = node(yytoken, NULL, NULL);292 np->sym = yylval.sym;293 np->addr = ASTR;294 next();295 break;296 case IDEN:297 c = ahead();298 if (c != EOS && c != ',')299 goto expression;300 np = node(IDEN, NULL, NULL);301 np->sym = yylval.sym;302 np->addr = ANUMBER;303 next();304 break;305 case '$':306 next();307 imm = 1;308 default:309 expression:310 if (!imm) {311 np = moperand();312 } else {313 np = expr();314 np->addr = AIMM;315 }316 }317 if (yytoken != ',' && yytoken != EOS)318 error("trailing characters in expression '%s'", textp);319 *strp = endp;320321 return np;322}323324Node **325getargs(char *s)326{327 Node **ap;328 static Node *args[NARGS];329330 if (!s)331 return NULL;332333 for (ap = args; ap < &args[NARGS-1]; ++ap) {334 if ((*ap = operand(&s)) == NULL)335 return args;336 }337 error("too many arguments in one instruction");338}339340static char *341field(char **oldp, size_t *siz)342{343 char *s, *t, *begin;344 size_t n;345346 if ((begin = *oldp) == NULL)347 return NULL;348349 for (s = begin; isspace(*s) && *s != '\t'; ++s)350 ;351 if (*s == '\0' || *s == '#') {352 *s = '\0';353 return *oldp = NULL;354 }355356 for (t = s; *t && *t != '\t'; ++t)357 ;358 if (*t == '\t')359 *t++ = '\0';360 *siz -= begin - t;361 *oldp = t;362363 while (t >= s && isspace(*t))364 *t-- = '\0';365 return (*s != '\0') ? s : NULL;366}367368static int369validlabel(char *name)370{371 int c;372373 while ((c = *name++) != '\0') {374 if (isalnum(c))375 continue;376 switch (c) {377 case '_':378 case '.':379 case '$':380 continue;381 case ':':382 if (*name != '\0')383 return 0;384 *--name = '\0';385 continue;386 default:387 return 0;388 }389 }390 return 1;391}392393static int394extract(char *s, size_t len, struct line *lp)395{396 int r = 0;397398 if (lp->label = field(&s, &len))399 r++;400 if (lp->op = field(&s, &len))401 r++;402 if (lp->args = field(&s, &len))403 r++;404405 if (s && *s && *s != '#')406 error("trailing characters at the end of the line");407 if (lp->label && !validlabel(lp->label))408 error("incorrect label name '%s'", lp->label);409410 return r;411}412413static size_t414getln(FILE *fp, char buff[MAXLINE])415{416 int c;417 char *bp;418419 for (bp = buff; (c = getc(fp)) != EOF; *bp++ = c) {420 if (c == '\n')421 break;422423 if (c > UCHAR_MAX)424 error("invalid character '%x'", c);425426 if (bp == &buff[MAXLINE-1])427 error("line too long");428 }429 *bp = '\0';430431 return bp - buff;432}433434int435nextline(struct line *lp)436{437 struct input *ip;438 size_t n;439 static char buff[MAXLINE];440441 assert(isp > inputs);442repeat:443 if (isp == inputs)444 return 0;445 ip = &isp[-1];446 if (feof(ip->fp)) {447 delinput();448 goto repeat;449 }450 n = getln(ip->fp, buff);451 if (++ip->lineno == 0)452 die("as: %s: file too long", infile);453 if (n == 0)454 goto repeat;455 if (extract(buff, n, lp) == 0)456 goto repeat;457 return 1;458}459460void461addinput(char *fname)462{463 FILE *fp;464465 if (isp == &inputs[NR_INPUTS])466 die("as: too many included files");467 if ((fp = fopen(fname, "r")) == NULL)468 die("as: %s: %s", fname, strerror(errno));469 isp->fname = xstrdup(fname);470 isp->fp = fp;471 isp->lineno = 0;472 ++isp;473}474475int476delinput(void)477{478 if (isp == inputs)479 return EOF;480 --isp;481 if (fclose(isp->fp) == EOF)482 die("as: %s: %s", isp->fname, strerror(errno));483 free(isp->fname);484 return 0;485}