summaryrefslogtreecommitdiff
path: root/src/cmd/5a
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/5a')
-rw-r--r--src/cmd/5a/Makefile25
-rw-r--r--src/cmd/5a/a.h200
-rw-r--r--src/cmd/5a/a.y710
-rw-r--r--src/cmd/5a/doc.go14
-rw-r--r--src/cmd/5a/lex.c704
5 files changed, 1653 insertions, 0 deletions
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile
new file mode 100644
index 000000000..f4463c97b
--- /dev/null
+++ b/src/cmd/5a/Makefile
@@ -0,0 +1,25 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=5a
+
+HFILES=\
+ a.h\
+ y.tab.h\
+ ../5l/5.out.h\
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+ ../5l/enam.$O\
+
+YFILES=\
+ a.y\
+
+include ../../Make.ccmd
+
+lex.$O: ../cc/macbody ../cc/lexbody
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
new file mode 100644
index 000000000..a2c87cf48
--- /dev/null
+++ b/src/cmd/5a/a.h
@@ -0,0 +1,200 @@
+// Inferno utils/5a/a.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.h
+//
+// 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.
+
+#include <bio.h>
+#include "../5l/5.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#undef getc
+#undef ungetc
+#undef BUFSIZ
+
+#define getc ccgetc
+#define ungetc ccungetc
+
+typedef struct Sym Sym;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 8192
+#define BUFSIZ 8192
+#define HISTSZ 20
+#ifndef EOF
+#define EOF (-1)
+#endif
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ char* macro;
+ int32 value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ Sym* sym;
+ int32 offset;
+ short type;
+ short reg;
+ short name;
+ double dval;
+ char sval[8];
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ int32 line;
+ int32 offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+
+ Always = 14,
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char** Dlist;
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char** include;
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN int32 lineno;
+EXTERN int nerrors;
+EXTERN int32 nhunk;
+EXTERN int ninclude;
+EXTERN int32 nsymb;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN int32 pc;
+EXTERN int peekc;
+EXTERN int32 stmtline;
+EXTERN int sym;
+EXTERN char* symb;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN int32 thunk;
+EXTERN Biobuf obuf;
+
+void* alloc(int32);
+void* allocn(void*, int32, int32);
+void ensuresymb(int32);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+int32 yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, int, Gen*, int, Gen*);
+void zname(char*, int, int);
+void zaddr(Gen*, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void maclin(void);
+void macprag(void);
+void macif(int);
+void macend(void);
+void outhist(void);
+void dodefine(char*);
+void prfile(int32);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
new file mode 100644
index 000000000..9a0efd5e0
--- /dev/null
+++ b/src/cmd/5a/a.y
@@ -0,0 +1,710 @@
+// Inferno utils/5a/a.y
+// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y
+//
+// 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.
+
+%{
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+%}
+%union
+{
+ Sym *sym;
+ int32 lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
+%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
+%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF
+%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
+%token <lval> LTYPEL LTYPEM LTYPEN LTYPEBX
+%token <lval> LCONST LSP LSB LFP LPC
+%token <lval> LTYPEX LR LREG LF LFREG LC LCREG LPSR LFCR
+%token <lval> LCOND LS LAT
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr oexpr pointer offset sreg spreg creg
+%type <lval> rcon cond reglist
+%type <gen> gen rel reg regreg freg shift fcon frcon
+%type <gen> imm ximm name oreg ireg nireg ioreg imsr
+%%
+prog:
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| LNAME '=' expr ';'
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr ';'
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * ADD
+ */
+ LTYPE1 cond imsr ',' spreg ',' reg
+ {
+ outcode($1, $2, &$3, $5, &$7);
+ }
+| LTYPE1 cond imsr ',' spreg ','
+ {
+ outcode($1, $2, &$3, $5, &nullgen);
+ }
+| LTYPE1 cond imsr ',' reg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+/*
+ * MVN
+ */
+| LTYPE2 cond imsr ',' reg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+/*
+ * MOVW
+ */
+| LTYPE3 cond gen ',' gen
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+/*
+ * B/BL
+ */
+| LTYPE4 cond comma rel
+ {
+ outcode($1, $2, &nullgen, NREG, &$4);
+ }
+| LTYPE4 cond comma nireg
+ {
+ outcode($1, $2, &nullgen, NREG, &$4);
+ }
+/*
+ * BX
+ */
+| LTYPEBX comma ireg
+ {
+ outcode($1, Always, &nullgen, NREG, &$3);
+ }
+/*
+ * BEQ
+ */
+| LTYPE5 comma rel
+ {
+ outcode($1, Always, &nullgen, NREG, &$3);
+ }
+/*
+ * SWI
+ */
+| LTYPE6 cond comma gen
+ {
+ outcode($1, $2, &nullgen, NREG, &$4);
+ }
+/*
+ * CMP
+ */
+| LTYPE7 cond imsr ',' spreg comma
+ {
+ outcode($1, $2, &$3, $5, &nullgen);
+ }
+/*
+ * MOVM
+ */
+| LTYPE8 cond ioreg ',' '[' reglist ']'
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $6;
+ outcode($1, $2, &$3, NREG, &g);
+ }
+| LTYPE8 cond '[' reglist ']' ',' ioreg
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $4;
+ outcode($1, $2, &g, NREG, &$7);
+ }
+/*
+ * SWAP
+ */
+| LTYPE9 cond reg ',' ireg ',' reg
+ {
+ outcode($1, $2, &$5, $3.reg, &$7);
+ }
+| LTYPE9 cond reg ',' ireg comma
+ {
+ outcode($1, $2, &$5, $3.reg, &$3);
+ }
+| LTYPE9 cond comma ireg ',' reg
+ {
+ outcode($1, $2, &$4, $6.reg, &$6);
+ }
+/*
+ * RET
+ */
+| LTYPEA cond comma
+ {
+ outcode($1, $2, &nullgen, NREG, &nullgen);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTYPEB name ',' imm
+ {
+ outcode($1, Always, &$2, NREG, &$4);
+ }
+| LTYPEB name ',' con ',' imm
+ {
+ outcode($1, Always, &$2, $4, &$6);
+ }
+/*
+ * DATA
+ */
+| LTYPEC name '/' con ',' ximm
+ {
+ outcode($1, Always, &$2, $4, &$6);
+ }
+/*
+ * CASE
+ */
+| LTYPED cond reg comma
+ {
+ outcode($1, $2, &$3, NREG, &nullgen);
+ }
+/*
+ * word
+ */
+| LTYPEH comma ximm
+ {
+ outcode($1, Always, &nullgen, NREG, &$3);
+ }
+/*
+ * floating-point coprocessor
+ */
+| LTYPEI cond freg ',' freg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+| LTYPEK cond frcon ',' freg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+| LTYPEK cond frcon ',' LFREG ',' freg
+ {
+ outcode($1, $2, &$3, $5, &$7);
+ }
+| LTYPEL cond freg ',' freg comma
+ {
+ outcode($1, $2, &$3, $5.reg, &nullgen);
+ }
+/*
+ * MCR MRC
+ */
+| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset =
+ (0xe << 24) | /* opcode */
+ ($1 << 20) | /* MCR/MRC */
+ ($2 << 28) | /* scond */
+ (($3 & 15) << 8) | /* coprocessor number */
+ (($5 & 7) << 21) | /* coprocessor operation */
+ (($7 & 15) << 12) | /* arm register */
+ (($9 & 15) << 16) | /* Crn */
+ (($11 & 15) << 0) | /* Crm */
+ (($12 & 7) << 5) | /* coprocessor information */
+ (1<<4); /* must be set */
+ outcode(AWORD, Always, &nullgen, NREG, &g);
+ }
+/*
+ * MULL hi,lo,r1,r2
+ */
+| LTYPEM cond reg ',' reg ',' regreg
+ {
+ outcode($1, $2, &$3, $5.reg, &$7);
+ }
+/*
+ * MULA hi,lo,r1,r2
+ */
+| LTYPEN cond reg ',' reg ',' reg ',' spreg
+ {
+ $7.type = D_REGREG;
+ $7.offset = $9;
+ outcode($1, $2, &$3, $5.reg, &$7);
+ }
+/*
+ * END
+ */
+| LTYPEE comma
+ {
+ outcode($1, Always, &nullgen, NREG, &nullgen);
+ }
+
+cond:
+ {
+ $$ = Always;
+ }
+| cond LCOND
+ {
+ $$ = ($1 & ~C_SCOND) | $2;
+ }
+| cond LS
+ {
+ $$ = $1 | $2;
+ }
+
+comma:
+| ',' comma
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+ximm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' oreg
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' '*' '$' oreg
+ {
+ $$ = $4;
+ $$.type = D_OCONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| fcon
+
+fcon:
+ '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+reglist:
+ spreg
+ {
+ $$ = 1 << $1;
+ }
+| spreg '-' spreg
+ {
+ int i;
+ $$=0;
+ for(i=$1; i<=$3; i++)
+ $$ |= 1<<i;
+ for(i=$3; i<=$1; i++)
+ $$ |= 1<<i;
+ }
+| spreg comma reglist
+ {
+ $$ = (1<<$1) | $3;
+ }
+
+gen:
+ reg
+| ximm
+| shift
+| shift '(' spreg ')'
+ {
+ $$ = $1;
+ $$.reg = $3;
+ }
+| LPSR
+ {
+ $$ = nullgen;
+ $$.type = D_PSR;
+ $$.reg = $1;
+ }
+| LFCR
+ {
+ $$ = nullgen;
+ $$.type = D_FPCR;
+ $$.reg = $1;
+ }
+| con
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.offset = $1;
+ }
+| oreg
+| freg
+
+nireg:
+ ireg
+| name
+ {
+ $$ = $1;
+ if($1.name != D_EXTERN && $1.name != D_STATIC) {
+ }
+ }
+
+ireg:
+ '(' spreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+
+ioreg:
+ ireg
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+oreg:
+ name
+| name '(' sreg ')'
+ {
+ $$ = $1;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ }
+| ioreg
+
+imsr:
+ reg
+| imm
+| shift
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+reg:
+ spreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+regreg:
+ '(' spreg ',' spreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_REGREG;
+ $$.reg = $2;
+ $$.offset = $4;
+ }
+
+shift:
+ spreg '<' '<' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (0 << 5);
+ }
+| spreg '>' '>' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (1 << 5);
+ }
+| spreg '-' '>' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (2 << 5);
+ }
+| spreg LAT '>' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (3 << 5);
+ }
+
+rcon:
+ spreg
+ {
+ if($$ < 0 || $$ >= 16)
+ print("register value out of range\n");
+ $$ = (($1&15) << 8) | (1 << 4);
+ }
+| con
+ {
+ if($$ < 0 || $$ >= 32)
+ print("shift value out of range\n");
+ $$ = ($1&31) << 7;
+ }
+
+sreg:
+ LREG
+| LPC
+ {
+ $$ = REGPC;
+ }
+| LR '(' expr ')'
+ {
+ if($3 < 0 || $3 >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+spreg:
+ sreg
+| LSP
+ {
+ $$ = REGSP;
+ }
+
+creg:
+ LCREG
+| LC '(' expr ')'
+ {
+ if($3 < 0 || $3 >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+frcon:
+ freg
+| fcon
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+oexpr:
+ {
+ $$ = 0;
+ }
+| ',' expr
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/src/cmd/5a/doc.go b/src/cmd/5a/doc.go
new file mode 100644
index 000000000..a0d2c4c64
--- /dev/null
+++ b/src/cmd/5a/doc.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+5a is a version of the Plan 9 assembler. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2a
+
+Its target architecture is the ARM, referred to by these tools as arm.
+
+*/
+package documentation
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
new file mode 100644
index 000000000..ad7ed05dd
--- /dev/null
+++ b/src/cmd/5a/lex.c
@@ -0,0 +1,704 @@
+// 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"