| // 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) | |
| { | |
| #ifdef _WIN32 | |
| return sys&Windows; | |
| #else | |
| return sys&Plan9; | |
| #endif | |
| } | |
| 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; | |
| if(systemtype(Windows) && p && p[1] == ':'){ | |
| c = p[2]; | |
| } else if(p && p[0] != c && h->offset == 0 && pathname){ | |
| if(systemtype(Windows) && pathname[1] == ':') { | |
| op = p; | |
| p = pathname; | |
| c = p[2]; | |
| } 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" |