| // Inferno utils/6a/a.h and lex.c. |
| // http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h |
| // http://code.google.com/p/inferno-os/source/browse/utils/6a/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. |
| |
| // Package asm holds code shared among the assemblers. |
| package asm |
| |
| import ( |
| "flag" |
| "fmt" |
| "log" |
| "os" |
| "path/filepath" |
| "strconv" |
| "strings" |
| |
| "cmd/internal/obj" |
| ) |
| |
| // Initialized by client. |
| var ( |
| LSCONST int |
| LCONST int |
| LFCONST int |
| LNAME int |
| LVAR int |
| LLAB int |
| |
| Thechar rune |
| Thestring string |
| Thelinkarch *obj.LinkArch |
| |
| Arches map[string]*obj.LinkArch |
| |
| Cclean func() |
| Yyparse func() |
| Syminit func(*Sym) |
| |
| Lexinit []Lextab |
| ) |
| |
| type Lextab struct { |
| Name string |
| Type int |
| Value int64 |
| } |
| |
| const ( |
| MAXALIGN = 7 |
| FPCHIP = 1 |
| NSYMB = 500 |
| BUFSIZ = 8192 |
| HISTSZ = 20 |
| EOF = -1 |
| IGN = -2 |
| NHASH = 503 |
| NMACRO = 10 |
| ) |
| |
| const ( |
| CLAST = iota |
| CMACARG |
| CMACRO |
| CPREPROC |
| ) |
| |
| type Macro struct { |
| Text string |
| Narg int |
| Dots bool |
| } |
| |
| type Sym struct { |
| Link *Sym |
| Ref *Ref |
| Macro *Macro |
| Value int64 |
| Type int |
| Name string |
| Labelname string |
| Sym int8 |
| } |
| |
| type Ref struct { |
| Class int |
| } |
| |
| type Io struct { |
| Link *Io |
| P []byte |
| F *os.File |
| B [1024]byte |
| } |
| |
| var fi struct { |
| P []byte |
| } |
| |
| var ( |
| debug [256]int |
| hash = map[string]*Sym{} |
| Dlist []string |
| newflag int |
| hunk string |
| include []string |
| iofree *Io |
| ionext *Io |
| iostack *Io |
| Lineno int32 |
| nerrors int |
| nhunk int32 |
| ninclude int |
| nsymb int32 |
| nullgen obj.Addr |
| outfile string |
| Pass int |
| PC int32 |
| peekc int = IGN |
| sym int |
| symb string |
| thunk int32 |
| obuf obj.Biobuf |
| Ctxt *obj.Link |
| bstdout obj.Biobuf |
| ) |
| |
| func dodef(p string) { |
| Dlist = append(Dlist, p) |
| } |
| |
| func usage() { |
| fmt.Printf("usage: %ca [options] file.c...\n", Thechar) |
| flag.PrintDefaults() |
| errorexit() |
| } |
| |
| func Main() { |
| // Allow GOARCH=Thestring or GOARCH=Thestringsuffix, |
| // but not other values. |
| p := obj.Getgoarch() |
| |
| if !strings.HasPrefix(p, Thestring) { |
| log.Fatalf("cannot use %cc with GOARCH=%s", Thechar, p) |
| } |
| if p != Thestring { |
| Thelinkarch = Arches[p] |
| if Thelinkarch == nil { |
| log.Fatalf("unknown arch %s", p) |
| } |
| } |
| |
| Ctxt = obj.Linknew(Thelinkarch) |
| Ctxt.Diag = Yyerror |
| Ctxt.Bso = &bstdout |
| Ctxt.Enforce_data_order = 1 |
| bstdout = *obj.Binitw(os.Stdout) |
| |
| debug = [256]int{} |
| cinit() |
| outfile = "" |
| setinclude(".") |
| |
| flag.Var(flagFn(dodef), "D", "name[=value]: add #define") |
| flag.Var(flagFn(setinclude), "I", "dir: add dir to include path") |
| flag.Var((*count)(&debug['S']), "S", "print assembly and machine code") |
| flag.Var((*count)(&debug['m']), "m", "debug preprocessor macros") |
| flag.StringVar(&outfile, "o", "", "file: set output file") |
| flag.StringVar(&Ctxt.Trimpath, "trimpath", "", "prefix: remove prefix from recorded source file paths") |
| |
| flag.Parse() |
| |
| Ctxt.Debugasm = int32(debug['S']) |
| |
| if flag.NArg() < 1 { |
| usage() |
| } |
| if flag.NArg() > 1 { |
| fmt.Printf("can't assemble multiple files\n") |
| errorexit() |
| } |
| |
| if assemble(flag.Arg(0)) != 0 { |
| errorexit() |
| } |
| obj.Bflush(&bstdout) |
| if nerrors > 0 { |
| errorexit() |
| } |
| } |
| |
| func assemble(file string) int { |
| if outfile == "" { |
| outfile = strings.TrimSuffix(filepath.Base(file), ".s") + "." + string(Thechar) |
| } |
| |
| of, err := os.Create(outfile) |
| if err != nil { |
| Yyerror("%ca: cannot create %s", Thechar, outfile) |
| errorexit() |
| } |
| |
| obuf = *obj.Binitw(of) |
| fmt.Fprintf(&obuf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion()) |
| fmt.Fprintf(&obuf, "!\n") |
| |
| var i int |
| for Pass = 1; Pass <= 2; Pass++ { |
| pinit(file) |
| for i = 0; i < len(Dlist); i++ { |
| dodefine(Dlist[i]) |
| } |
| Yyparse() |
| Cclean() |
| if nerrors != 0 { |
| return nerrors |
| } |
| } |
| |
| obj.Writeobjdirect(Ctxt, &obuf) |
| obj.Bflush(&obuf) |
| return 0 |
| } |
| |
| func cinit() { |
| for i := 0; i < len(Lexinit); i++ { |
| s := Lookup(Lexinit[i].Name) |
| if s.Type != LNAME { |
| Yyerror("double initialization %s", Lexinit[i].Name) |
| } |
| s.Type = Lexinit[i].Type |
| s.Value = Lexinit[i].Value |
| } |
| } |
| |
| func syminit(s *Sym) { |
| s.Type = LNAME |
| s.Value = 0 |
| } |
| |
| type flagFn func(string) |
| |
| func (flagFn) String() string { |
| return "<arg>" |
| } |
| |
| func (f flagFn) Set(s string) error { |
| f(s) |
| return nil |
| } |
| |
| type yyImpl struct{} |
| |
| // count is a flag.Value that is like a flag.Bool and a flag.Int. |
| // If used as -name, it increments the count, but -name=x sets the count. |
| // Used for verbose flag -v. |
| type count int |
| |
| func (c *count) String() string { |
| return fmt.Sprint(int(*c)) |
| } |
| |
| func (c *count) Set(s string) error { |
| switch s { |
| case "true": |
| *c++ |
| case "false": |
| *c = 0 |
| default: |
| n, err := strconv.Atoi(s) |
| if err != nil { |
| return fmt.Errorf("invalid count %q", s) |
| } |
| *c = count(n) |
| } |
| return nil |
| } |
| |
| func (c *count) IsBoolFlag() bool { |
| return true |
| } |