blob: ad7ed05ddd90f2a1ddf47c82552a1d2b00cc21ee [file] [log] [blame]
// Inferno utils/5a/lex.c
// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#define EXTERN
#include <u.h>
#include <libc.h>
#include "a.h"
#include "y.tab.h"
enum
{
Plan9 = 1<<0,
Unix = 1<<1,
Windows = 1<<2,
};
int
systemtype(int sys)
{
return sys&Plan9;
}
void
main(int argc, char *argv[])
{
char *p;
int c;
thechar = '5';
thestring = "arm";
ensuresymb(NSYMB);
memset(debug, 0, sizeof(debug));
cinit();
outfile = 0;
setinclude(".");
ARGBEGIN {
default:
c = ARGC();
if(c >= 0 || c < sizeof(debug))
debug[c] = 1;
break;
case 'o':
outfile = ARGF();
break;
case 'D':
p = ARGF();
if(p) {
if (nDlist%8 == 0)
Dlist = allocn(Dlist, nDlist*sizeof(char *),
8*sizeof(char *));
Dlist[nDlist++] = p;
}
break;
case 'I':
p = ARGF();
setinclude(p);
break;
case 't':
thechar = 't';
thestring = "thumb";
break;
} ARGEND
if(*argv == 0) {
print("usage: %ca [-options] file.s\n", thechar);
errorexit();
}
if(argc > 1){
print("can't assemble multiple files\n");
errorexit();
}
if(assemble(argv[0]))
errorexit();
exits(0);
}
int
assemble(char *file)
{
char *ofile, *p;
int i, of;
ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
strcpy(ofile, file);
p = utfrrune(ofile, '/');
if(p) {
include[0] = ofile;
*p++ = 0;
} else
p = ofile;
if(outfile == 0) {
outfile = p;
if(outfile){
p = utfrrune(outfile, '.');
if(p)
if(p[1] == 's' && p[2] == 0)
p[0] = 0;
p = utfrune(outfile, 0);
p[0] = '.';
p[1] = thechar;
p[2] = 0;
} else
outfile = "/dev/null";
}
of = create(outfile, OWRITE, 0664);
if(of < 0) {
yyerror("%ca: cannot create %s", thechar, outfile);
errorexit();
}
Binit(&obuf, of, OWRITE);
pass = 1;
pinit(file);
Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
for(i=0; i<nDlist; i++)
dodefine(Dlist[i]);
yyparse();
if(nerrors) {
cclean();
return nerrors;
}
Bprint(&obuf, "\n!\n");
pass = 2;
outhist();
pinit(file);
for(i=0; i<nDlist; i++)
dodefine(Dlist[i]);
yyparse();
cclean();
return nerrors;
}
struct
{
char *name;
ushort type;
ushort value;
} itab[] =
{
"SP", LSP, D_AUTO,
"SB", LSB, D_EXTERN,
"FP", LFP, D_PARAM,
"PC", LPC, D_BRANCH,
"R", LR, 0,
"R0", LREG, 0,
"R1", LREG, 1,
"R2", LREG, 2,
"R3", LREG, 3,
"R4", LREG, 4,
"R5", LREG, 5,
"R6", LREG, 6,
"R7", LREG, 7,
"R8", LREG, 8,
"R9", LREG, 9,
"R10", LREG, 10,
"R11", LREG, 11,
"R12", LREG, 12,
"R13", LREG, 13,
"R14", LREG, 14,
"R15", LREG, 15,
"F", LF, 0,
"F0", LFREG, 0,
"F1", LFREG, 1,
"F2", LFREG, 2,
"F3", LFREG, 3,
"F4", LFREG, 4,
"F5", LFREG, 5,
"F6", LFREG, 6,
"F7", LFREG, 7,
"F8", LFREG, 8,
"F9", LFREG, 9,
"F10", LFREG, 10,
"F11", LFREG, 11,
"F12", LFREG, 12,
"F13", LFREG, 13,
"F14", LFREG, 14,
"F15", LFREG, 15,
"C", LC, 0,
"C0", LCREG, 0,
"C1", LCREG, 1,
"C2", LCREG, 2,
"C3", LCREG, 3,
"C4", LCREG, 4,
"C5", LCREG, 5,
"C6", LCREG, 6,
"C7", LCREG, 7,
"C8", LCREG, 8,
"C9", LCREG, 9,
"C10", LCREG, 10,
"C11", LCREG, 11,
"C12", LCREG, 12,
"C13", LCREG, 13,
"C14", LCREG, 14,
"C15", LCREG, 15,
"CPSR", LPSR, 0,
"SPSR", LPSR, 1,
"FPSR", LFCR, 0,
"FPCR", LFCR, 1,
".EQ", LCOND, 0,
".NE", LCOND, 1,
".CS", LCOND, 2,
".HS", LCOND, 2,
".CC", LCOND, 3,
".LO", LCOND, 3,
".MI", LCOND, 4,
".PL", LCOND, 5,
".VS", LCOND, 6,
".VC", LCOND, 7,
".HI", LCOND, 8,
".LS", LCOND, 9,
".GE", LCOND, 10,
".LT", LCOND, 11,
".GT", LCOND, 12,
".LE", LCOND, 13,
".AL", LCOND, Always,
".U", LS, C_UBIT,
".S", LS, C_SBIT,
".W", LS, C_WBIT,
".P", LS, C_PBIT,
".PW", LS, C_WBIT|C_PBIT,
".WP", LS, C_WBIT|C_PBIT,
".F", LS, C_FBIT,
".IBW", LS, C_WBIT|C_PBIT|C_UBIT,
".IAW", LS, C_WBIT|C_UBIT,
".DBW", LS, C_WBIT|C_PBIT,
".DAW", LS, C_WBIT,
".IB", LS, C_PBIT|C_UBIT,
".IA", LS, C_UBIT,
".DB", LS, C_PBIT,
".DA", LS, 0,
"@", LAT, 0,
"AND", LTYPE1, AAND,
"EOR", LTYPE1, AEOR,
"SUB", LTYPE1, ASUB,
"RSB", LTYPE1, ARSB,
"ADD", LTYPE1, AADD,
"ADC", LTYPE1, AADC,
"SBC", LTYPE1, ASBC,
"RSC", LTYPE1, ARSC,
"ORR", LTYPE1, AORR,
"BIC", LTYPE1, ABIC,
"SLL", LTYPE1, ASLL,
"SRL", LTYPE1, ASRL,
"SRA", LTYPE1, ASRA,
"MUL", LTYPE1, AMUL,
"MULA", LTYPEN, AMULA,
"DIV", LTYPE1, ADIV,
"MOD", LTYPE1, AMOD,
"MULL", LTYPEM, AMULL,
"MULAL", LTYPEM, AMULAL,
"MULLU", LTYPEM, AMULLU,
"MULALU", LTYPEM, AMULALU,
"MVN", LTYPE2, AMVN, /* op2 ignored */
"MOVB", LTYPE3, AMOVB,
"MOVBU", LTYPE3, AMOVBU,
"MOVH", LTYPE3, AMOVH,
"MOVHU", LTYPE3, AMOVHU,
"MOVW", LTYPE3, AMOVW,
"MOVD", LTYPE3, AMOVD,
"MOVDF", LTYPE3, AMOVDF,
"MOVDW", LTYPE3, AMOVDW,
"MOVF", LTYPE3, AMOVF,
"MOVFD", LTYPE3, AMOVFD,
"MOVFW", LTYPE3, AMOVFW,
"MOVWD", LTYPE3, AMOVWD,
"MOVWF", LTYPE3, AMOVWF,
"LDREX", LTYPE3, ALDREX,
"LDREXD", LTYPE3, ALDREXD,
"STREX", LTYPE9, ASTREX,
"STREXD", LTYPE9, ASTREXD,
/*
"ABSF", LTYPEI, AABSF,
"ABSD", LTYPEI, AABSD,
"NEGF", LTYPEI, ANEGF,
"NEGD", LTYPEI, ANEGD,
"SQTF", LTYPEI, ASQTF,
"SQTD", LTYPEI, ASQTD,
"RNDF", LTYPEI, ARNDF,
"RNDD", LTYPEI, ARNDD,
"URDF", LTYPEI, AURDF,
"URDD", LTYPEI, AURDD,
"NRMF", LTYPEI, ANRMF,
"NRMD", LTYPEI, ANRMD,
*/
"SQRTF", LTYPEI, ASQRTF,
"SQRTD", LTYPEI, ASQRTD,
"CMPF", LTYPEL, ACMPF,
"CMPD", LTYPEL, ACMPD,
"ADDF", LTYPEK, AADDF,
"ADDD", LTYPEK, AADDD,
"SUBF", LTYPEK, ASUBF,
"SUBD", LTYPEK, ASUBD,
"MULF", LTYPEK, AMULF,
"MULD", LTYPEK, AMULD,
"DIVF", LTYPEK, ADIVF,
"DIVD", LTYPEK, ADIVD,
"B", LTYPE4, AB,
"BL", LTYPE4, ABL,
"BX", LTYPEBX, ABX,
"BEQ", LTYPE5, ABEQ,
"BNE", LTYPE5, ABNE,
"BCS", LTYPE5, ABCS,
"BHS", LTYPE5, ABHS,
"BCC", LTYPE5, ABCC,
"BLO", LTYPE5, ABLO,
"BMI", LTYPE5, ABMI,
"BPL", LTYPE5, ABPL,
"BVS", LTYPE5, ABVS,
"BVC", LTYPE5, ABVC,
"BHI", LTYPE5, ABHI,
"BLS", LTYPE5, ABLS,
"BGE", LTYPE5, ABGE,
"BLT", LTYPE5, ABLT,
"BGT", LTYPE5, ABGT,
"BLE", LTYPE5, ABLE,
"BCASE", LTYPE5, ABCASE,
"SWI", LTYPE6, ASWI,
"CMP", LTYPE7, ACMP,
"TST", LTYPE7, ATST,
"TEQ", LTYPE7, ATEQ,
"CMN", LTYPE7, ACMN,
"MOVM", LTYPE8, AMOVM,
"SWPBU", LTYPE9, ASWPBU,
"SWPW", LTYPE9, ASWPW,
"RET", LTYPEA, ARET,
"RFE", LTYPEA, ARFE,
"TEXT", LTYPEB, ATEXT,
"GLOBL", LTYPEB, AGLOBL,
"DATA", LTYPEC, ADATA,
"CASE", LTYPED, ACASE,
"END", LTYPEE, AEND,
"WORD", LTYPEH, AWORD,
"NOP", LTYPEI, ANOP,
"MCR", LTYPEJ, 0,
"MRC", LTYPEJ, 1,
0
};
void
cinit(void)
{
Sym *s;
int i;
nullgen.sym = S;
nullgen.offset = 0;
nullgen.type = D_NONE;
nullgen.name = D_NONE;
nullgen.reg = NREG;
if(FPCHIP)
nullgen.dval = 0;
for(i=0; i<sizeof(nullgen.sval); i++)
nullgen.sval[i] = 0;
nerrors = 0;
iostack = I;
iofree = I;
peekc = IGN;
nhunk = 0;
for(i=0; i<NHASH; i++)
hash[i] = S;
for(i=0; itab[i].name; i++) {
s = slookup(itab[i].name);
s->type = itab[i].type;
s->value = itab[i].value;
}
pathname = allocn(pathname, 0, 100);
if(getwd(pathname, 99) == 0) {
pathname = allocn(pathname, 100, 900);
if(getwd(pathname, 999) == 0)
strcpy(pathname, "/???");
}
}
void
syminit(Sym *s)
{
s->type = LNAME;
s->value = 0;
}
int
isreg(Gen *g)
{
USED(g);
return 1;
}
void
cclean(void)
{
outcode(AEND, Always, &nullgen, NREG, &nullgen);
Bflush(&obuf);
}
void
zname(char *n, int t, int s)
{
Bputc(&obuf, ANAME);
Bputc(&obuf, t); /* type */
Bputc(&obuf, s); /* sym */
while(*n) {
Bputc(&obuf, *n);
n++;
}
Bputc(&obuf, 0);
}
void
zaddr(Gen *a, int s)
{
int32 l;
int i;
char *n;
Ieee e;
Bputc(&obuf, a->type);
Bputc(&obuf, a->reg);
Bputc(&obuf, s);
Bputc(&obuf, a->name);
switch(a->type) {
default:
print("unknown type %d\n", a->type);
exits("arg");
case D_NONE:
case D_REG:
case D_FREG:
case D_PSR:
case D_FPCR:
break;
case D_REGREG:
Bputc(&obuf, a->offset);
break;
case D_OREG:
case D_CONST:
case D_BRANCH:
case D_SHIFT:
l = a->offset;
Bputc(&obuf, l);
Bputc(&obuf, l>>8);
Bputc(&obuf, l>>16);
Bputc(&obuf, l>>24);
break;
case D_SCONST:
n = a->sval;
for(i=0; i<NSNAME; i++) {
Bputc(&obuf, *n);
n++;
}
break;
case D_FCONST:
ieeedtod(&e, a->dval);
Bputc(&obuf, e.l);
Bputc(&obuf, e.l>>8);
Bputc(&obuf, e.l>>16);
Bputc(&obuf, e.l>>24);
Bputc(&obuf, e.h);
Bputc(&obuf, e.h>>8);
Bputc(&obuf, e.h>>16);
Bputc(&obuf, e.h>>24);
break;
}
}
static int bcode[] =
{
ABEQ,
ABNE,
ABCS,
ABCC,
ABMI,
ABPL,
ABVS,
ABVC,
ABHI,
ABLS,
ABGE,
ABLT,
ABGT,
ABLE,
AB,
ANOP,
};
void
outcode(int a, int scond, Gen *g1, int reg, Gen *g2)
{
int sf, st, t;
Sym *s;
/* hack to make B.NE etc. work: turn it into the corresponding conditional */
if(a == AB){
a = bcode[scond&0xf];
scond = (scond & ~0xf) | Always;
}
if(pass == 1)
goto out;
jackpot:
sf = 0;
s = g1->sym;
while(s != S) {
sf = s->sym;
if(sf < 0 || sf >= NSYM)
sf = 0;
t = g1->name;
if(h[sf].type == t)
if(h[sf].sym == s)
break;
zname(s->name, t, sym);
s->sym = sym;
h[sym].sym = s;
h[sym].type = t;
sf = sym;
sym++;
if(sym >= NSYM)
sym = 1;
break;
}
st = 0;
s = g2->sym;
while(s != S) {
st = s->sym;
if(st < 0 || st >= NSYM)
st = 0;
t = g2->name;
if(h[st].type == t)
if(h[st].sym == s)
break;
zname(s->name, t, sym);
s->sym = sym;
h[sym].sym = s;
h[sym].type = t;
st = sym;
sym++;
if(sym >= NSYM)
sym = 1;
if(st == sf)
goto jackpot;
break;
}
Bputc(&obuf, a);
Bputc(&obuf, scond);
Bputc(&obuf, reg);
Bputc(&obuf, stmtline);
Bputc(&obuf, stmtline>>8);
Bputc(&obuf, stmtline>>16);
Bputc(&obuf, stmtline>>24);
zaddr(g1, sf);
zaddr(g2, st);
out:
if(a != AGLOBL && a != ADATA)
pc++;
}
void
outhist(void)
{
Gen g;
Hist *h;
char *p, *q, *op, c;
int n;
g = nullgen;
c = '/';
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
/* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
p += 2;
c = *p;
}
if(p && p[0] != c && h->offset == 0 && pathname){
/* on windows skip drive specifier in pathname */
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
p = pathname+2;
c = *p;
} else if(pathname[0] == c){
op = p;
p = pathname;
}
}
while(p) {
q = strchr(p, c);
if(q) {
n = q-p;
if(n == 0){
n = 1; /* leading "/" */
*p = '/'; /* don't emit "\" on windows */
}
q++;
} else {
n = strlen(p);
q = 0;
}
if(n) {
Bputc(&obuf, ANAME);
Bputc(&obuf, D_FILE); /* type */
Bputc(&obuf, 1); /* sym */
Bputc(&obuf, '<');
Bwrite(&obuf, p, n);
Bputc(&obuf, 0);
}
p = q;
if(p == 0 && op) {
p = op;
op = 0;
}
}
g.offset = h->offset;
Bputc(&obuf, AHISTORY);
Bputc(&obuf, Always);
Bputc(&obuf, 0);
Bputc(&obuf, h->line);
Bputc(&obuf, h->line>>8);
Bputc(&obuf, h->line>>16);
Bputc(&obuf, h->line>>24);
zaddr(&nullgen, 0);
zaddr(&g, 0);
}
}
#include "../cc/lexbody"
#include "../cc/macbody"