| // 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; |
| char *tofree; |
| static int first = 1; |
| static char *goroot, *goroot_final; |
| |
| if(first) { |
| // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. |
| first = 0; |
| goroot = getenv("GOROOT"); |
| goroot_final = getenv("GOROOT_FINAL"); |
| if(goroot == nil) |
| goroot = ""; |
| if(goroot_final == nil) |
| goroot_final = goroot; |
| if(strcmp(goroot, goroot_final) == 0) { |
| goroot = nil; |
| goroot_final = nil; |
| } |
| } |
| |
| tofree = nil; |
| g = nullgen; |
| c = '/'; |
| for(h = hist; h != H; h = h->link) { |
| p = h->name; |
| if(p != nil && goroot != nil) { |
| n = strlen(goroot); |
| if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { |
| tofree = smprint("%s%s", goroot_final, p+n); |
| p = tofree; |
| } |
| } |
| 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); |
| |
| if(tofree) { |
| free(tofree); |
| tofree = nil; |
| } |
| } |
| } |
| |
| #include "../cc/lexbody" |
| #include "../cc/macbody" |