| // 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 |
| } |
| |
| int |
| Lconv(Fmt *fp) |
| { |
| return linklinefmt(ctxt, fp); |
| } |
| |
| void |
| dodef(char *p) |
| { |
| if(nDlist%8 == 0) |
| Dlist = allocn(Dlist, nDlist*sizeof(char *), |
| 8*sizeof(char *)); |
| Dlist[nDlist++] = p; |
| } |
| |
| void |
| usage(void) |
| { |
| print("usage: %ca [options] file.c...\n", thechar); |
| flagprint(1); |
| errorexit(); |
| } |
| |
| void |
| main(int argc, char *argv[]) |
| { |
| char *p; |
| |
| thechar = '5'; |
| thestring = "arm"; |
| |
| ctxt = linknew(&linkarm); |
| ctxt->diag = yyerror; |
| ctxt->bso = &bstdout; |
| Binit(&bstdout, 1, OWRITE); |
| listinit5(); |
| fmtinstall('L', Lconv); |
| |
| // Allow GOARCH=thestring or GOARCH=thestringsuffix, |
| // but not other values. |
| p = getgoarch(); |
| if(strncmp(p, thestring, strlen(thestring)) != 0) |
| sysfatal("cannot use %cc with GOARCH=%s", thechar, p); |
| |
| ensuresymb(NSYMB); |
| memset(debug, 0, sizeof(debug)); |
| cinit(); |
| outfile = 0; |
| setinclude("."); |
| |
| flagfn1("D", "name[=value]: add #define", dodef); |
| flagfn1("I", "dir: add dir to include path", setinclude); |
| flagcount("S", "print assembly and machine code", &debug['S']); |
| flagcount("m", "debug preprocessor macros", &debug['m']); |
| flagstr("o", "file: set output file", &outfile); |
| flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); |
| |
| flagparse(&argc, &argv, usage); |
| ctxt->debugasm = debug['S']; |
| |
| if(argc < 1) |
| usage(); |
| if(argc > 1){ |
| print("can't assemble multiple files\n"); |
| errorexit(); |
| } |
| |
| if(assemble(argv[0])) |
| errorexit(); |
| Bflush(&bstdout); |
| 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); |
| Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); |
| Bprint(&obuf, "!\n"); |
| |
| for(pass = 1; pass <= 2; pass++) { |
| pinit(file); |
| for(i=0; i<nDlist; i++) |
| dodefine(Dlist[i]); |
| yyparse(); |
| cclean(); |
| if(nerrors) |
| return nerrors; |
| } |
| |
| writeobj(ctxt, &obuf); |
| Bflush(&obuf); |
| return 0; |
| } |
| |
| 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, |
| "m", LREG, 9, // avoid unintentionally clobber m/g using R9/R10 |
| "g", 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, |
| |
| /* |
| "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, |
| */ |
| |
| "ABSF", LTYPEI, AABSF, |
| "ABSD", LTYPEI, AABSD, |
| "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, |
| |
| "PLD", LTYPEPLD, APLD, |
| "UNDEF", LTYPEE, AUNDEF, |
| "CLZ", LTYPE2, ACLZ, |
| |
| "MULWT", LTYPE1, AMULWT, |
| "MULWB", LTYPE1, AMULWB, |
| "MULAWT", LTYPEN, AMULAWT, |
| "MULAWB", LTYPEN, AMULAWB, |
| |
| "USEFIELD", LTYPEN, AUSEFIELD, |
| "PCDATA", LTYPEPC, APCDATA, |
| "FUNCDATA", LTYPEF, AFUNCDATA, |
| |
| 0 |
| }; |
| |
| void |
| cinit(void) |
| { |
| Sym *s; |
| int i; |
| |
| nullgen.type = D_NONE; |
| nullgen.name = D_NONE; |
| nullgen.reg = NREG; |
| |
| 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; |
| } |
| } |
| |
| void |
| syminit(Sym *s) |
| { |
| |
| s->type = LNAME; |
| s->value = 0; |
| } |
| |
| int |
| isreg(Addr *g) |
| { |
| |
| USED(g); |
| return 1; |
| } |
| |
| void |
| cclean(void) |
| { |
| outcode(AEND, Always, &nullgen, NREG, &nullgen); |
| } |
| |
| static int bcode[] = |
| { |
| ABEQ, |
| ABNE, |
| ABCS, |
| ABCC, |
| ABMI, |
| ABPL, |
| ABVS, |
| ABVC, |
| ABHI, |
| ABLS, |
| ABGE, |
| ABLT, |
| ABGT, |
| ABLE, |
| AB, |
| ANOP, |
| }; |
| |
| static Prog *lastpc; |
| |
| void |
| outcode(int a, int scond, Addr *g1, int reg, Addr *g2) |
| { |
| Prog *p; |
| Plist *pl; |
| |
| /* 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; |
| |
| p = malloc(sizeof *p); |
| memset(p, 0, sizeof *p); |
| p->as = a; |
| p->lineno = stmtline; |
| p->scond = scond; |
| p->from = *g1; |
| p->reg = reg; |
| p->to = *g2; |
| p->pc = pc; |
| |
| if(lastpc == nil) { |
| pl = linknewplist(ctxt); |
| pl->firstpc = p; |
| } else |
| lastpc->link = p; |
| lastpc = p; |
| |
| out: |
| if(a != AGLOBL && a != ADATA) |
| pc++; |
| } |
| |
| #include "../cc/lexbody" |
| #include "../cc/macbody" |