Commit 861af804 authored by Mikio Hara's avatar Mikio Hara

cmd/internal/asm: delete

Updates #10510.

Change-Id: Ib4d39943969d18517b373292b83d87650d5df12a
Reviewed-on: https://go-review.googlesource.com/12787
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent ba0c142d
// 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.LineHist.TrimPathPrefix, "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()
}
bstdout.Flush()
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)
obuf.Flush()
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
}
// Inferno utils/cc/lexbody
// http://code.Google.Com/p/inferno-os/source/browse/utils/cc/lexbody
//
// 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
import (
"bytes"
"fmt"
"os"
"strconv"
"strings"
"unicode/utf8"
"cmd/internal/obj"
)
/*
* common code for all the assemblers
*/
func pragpack() {
for getnsc() != '\n' {
}
}
func pragvararg() {
for getnsc() != '\n' {
}
}
func pragcgo(name string) {
for getnsc() != '\n' {
}
}
func pragfpround() {
for getnsc() != '\n' {
}
}
func pragtextflag() {
for getnsc() != '\n' {
}
}
func pragdataflag() {
for getnsc() != '\n' {
}
}
func pragprofile() {
for getnsc() != '\n' {
}
}
func pragincomplete() {
for getnsc() != '\n' {
}
}
func setinclude(p string) {
if p == "" {
return
}
for i := 1; i < len(include); i++ {
if p == include[i] {
return
}
}
include = append(include, p)
}
func errorexit() {
bstdout.Flush()
if outfile != "" {
os.Remove(outfile)
}
os.Exit(2)
}
func pushio() {
i := iostack
if i == nil {
Yyerror("botch in pushio")
errorexit()
}
i.P = fi.P
}
func newio() {
var pushdepth int = 0
i := iofree
if i == nil {
pushdepth++
if pushdepth > 1000 {
Yyerror("macro/io expansion too deep")
errorexit()
}
i = new(Io)
} else {
iofree = i.Link
}
i.F = nil
i.P = nil
ionext = i
}
func newfile(s string, f *os.File) {
i := ionext
i.Link = iostack
iostack = i
i.F = f
if f == nil {
var err error
i.F, err = os.Open(s)
if err != nil {
Yyerror("%ca: %v", Thechar, err)
errorexit()
}
}
fi.P = nil
Ctxt.LineHist.Push(int(Lineno), s)
}
var thetext *obj.LSym
func Settext(s *obj.LSym) {
thetext = s
}
func LabelLookup(s *Sym) *Sym {
if thetext == nil {
s.Labelname = s.Name
return s
}
p := string(fmt.Sprintf("%s.%s", thetext.Name, s.Name))
lab := Lookup(p)
lab.Labelname = s.Name
return lab
}
func Lookup(symb string) *Sym {
// turn leading · into ""·
if strings.HasPrefix(symb, "·") {
symb = `""` + symb
}
// turn · (U+00B7) into .
// turn ∕ (U+2215) into /
symb = strings.Replace(symb, "·", ".", -1)
symb = strings.Replace(symb, "∕", "/", -1)
s := hash[symb]
if s != nil {
return s
}
s = new(Sym)
s.Name = symb
syminit(s)
hash[symb] = s
return s
}
func isalnum(c int) bool {
return isalpha(c) || isdigit(c)
}
func isalpha(c int) bool {
return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
}
func isspace(c int) bool {
return c == ' ' || c == '\t' || c == '\r' || c == '\n'
}
func ISALPHA(c int) bool {
if isalpha(c) {
return true
}
if c >= utf8.RuneSelf {
return true
}
return false
}
var yybuf bytes.Buffer
func (yyImpl) Error(s string) {
Yyerror("%s", s)
}
type Yylval struct {
Sym *Sym
Lval int64
Sval string
Dval float64
}
func Yylex(yylval *Yylval) int {
var c1 int
var s *Sym
c := peekc
if c != IGN {
peekc = IGN
goto l1
}
l0:
c = GETC()
l1:
if c == EOF {
peekc = EOF
return -1
}
if isspace(c) {
if c == '\n' {
Lineno++
return ';'
}
goto l0
}
if ISALPHA(c) {
yybuf.Reset()
goto aloop
}
if isdigit(c) {
yybuf.Reset()
if c != '0' {
goto dc
}
yybuf.WriteByte(byte(c))
c = GETC()
c1 = 3
if c == 'x' || c == 'X' {
c1 = 4
c = GETC()
} else if c < '0' || c > '7' {
goto dc
}
yylval.Lval = 0
for {
if c >= '0' && c <= '9' {
if c > '7' && c1 == 3 {
break
}
yylval.Lval = int64(uint64(yylval.Lval) << uint(c1))
yylval.Lval += int64(c) - '0'
c = GETC()
continue
}
if c1 == 3 {
break
}
if c >= 'A' && c <= 'F' {
c += 'a' - 'A'
}
if c >= 'a' && c <= 'f' {
yylval.Lval = int64(uint64(yylval.Lval) << uint(c1))
yylval.Lval += int64(c) - 'a' + 10
c = GETC()
continue
}
break
}
goto ncu
}
switch c {
case '\n':
Lineno++
return ';'
case '#':
domacro()
goto l0
case '.':
c = GETC()
if ISALPHA(c) {
yybuf.Reset()
yybuf.WriteByte('.')
goto aloop
}
if isdigit(c) {
yybuf.Reset()
yybuf.WriteByte('.')
goto casedot
}
peekc = c
return '.'
case '_',
'@':
yybuf.Reset()
goto aloop
case '"':
var buf bytes.Buffer
c1 = 0
for {
c = escchar('"')
if c == EOF {
break
}
buf.WriteByte(byte(c))
}
yylval.Sval = buf.String()
return LSCONST
case '\'':
c = escchar('\'')
if c == EOF {
c = '\''
}
if escchar('\'') != EOF {
Yyerror("missing '")
}
yylval.Lval = int64(c)
return LCONST
case '/':
c1 = GETC()
if c1 == '/' {
for {
c = GETC()
if c == '\n' {
goto l1
}
if c == EOF {
Yyerror("eof in comment")
errorexit()
}
}
}
if c1 == '*' {
for {
c = GETC()
for c == '*' {
c = GETC()
if c == '/' {
goto l0
}
}
if c == EOF {
Yyerror("eof in comment")
errorexit()
}
if c == '\n' {
Lineno++
}
}
}
default:
return int(c)
}
peekc = c1
return int(c)
casedot:
for {
yybuf.WriteByte(byte(c))
c = GETC()
if !(isdigit(c)) {
break
}
}
if c == 'e' || c == 'E' {
goto casee
}
goto caseout
casee:
yybuf.WriteByte('e')
c = GETC()
if c == '+' || c == '-' {
yybuf.WriteByte(byte(c))
c = GETC()
}
for isdigit(c) {
yybuf.WriteByte(byte(c))
c = GETC()
}
caseout:
peekc = c
if FPCHIP != 0 /*TypeKind(100016)*/ {
last = yybuf.String()
yylval.Dval = atof(last)
return LFCONST
}
Yyerror("assembler cannot interpret fp constants")
yylval.Lval = 1
return LCONST
aloop:
yybuf.WriteByte(byte(c))
c = GETC()
if ISALPHA(c) || isdigit(c) || c == '_' || c == '$' {
goto aloop
}
peekc = c
last = yybuf.String()
s = Lookup(last)
if s.Macro != nil {
newio()
ionext.P = macexpand(s)
pushio()
ionext.Link = iostack
iostack = ionext
fi.P = ionext.P
if peekc != IGN {
fi.P = append(fi.P, byte(peekc))
peekc = IGN
}
goto l0
}
if s.Type == 0 {
s.Type = LNAME
}
if s.Type == LNAME || s.Type == LVAR || s.Type == LLAB {
yylval.Sym = s
yylval.Sval = last
return int(s.Type)
}
yylval.Lval = s.Value
yylval.Sval = last
return int(s.Type)
dc:
for {
if !(isdigit(c)) {
break
}
yybuf.WriteByte(byte(c))
c = GETC()
}
if c == '.' {
goto casedot
}
if c == 'e' || c == 'E' {
goto casee
}
last = yybuf.String()
yylval.Lval = strtoll(last, nil, 10)
ncu:
for c == 'U' || c == 'u' || c == 'l' || c == 'L' {
c = GETC()
}
peekc = c
return LCONST
}
func getc() int {
c := peekc
if c != IGN {
peekc = IGN
if c == '\n' {
Lineno++
}
return c
}
c = GETC()
if c == '\n' {
Lineno++
}
if c == EOF {
Yyerror("End of file")
errorexit()
}
return c
}
func getnsc() int {
var c int
for {
c = getc()
if !isspace(c) || c == '\n' {
return c
}
}
}
func unget(c int) {
peekc = c
if c == '\n' {
Lineno--
}
}
func escchar(e int) int {
var l int
loop:
c := getc()
if c == '\n' {
Yyerror("newline in string")
return EOF
}
if c != '\\' {
if c == e {
return EOF
}
return c
}
c = getc()
if c >= '0' && c <= '7' {
l = c - '0'
c = getc()
if c >= '0' && c <= '7' {
l = l*8 + c - '0'
c = getc()
if c >= '0' && c <= '7' {
l = l*8 + c - '0'
return l
}
}
peekc = c
unget(c)
return l
}
switch c {
case '\n':
goto loop
case 'n':
return '\n'
case 't':
return '\t'
case 'b':
return '\b'
case 'r':
return '\r'
case 'f':
return '\f'
case 'a':
return 0x07
case 'v':
return 0x0b
case 'z':
return 0x00
}
return c
}
func pinit(f string) {
Lineno = 1
newio()
newfile(f, nil)
PC = 0
peekc = IGN
sym = 1
for _, s := range hash {
s.Macro = nil
}
}
func filbuf() int {
var n int
loop:
i := iostack
if i == nil {
return EOF
}
if i.F == nil {
goto pop
}
n, _ = i.F.Read(i.B[:])
if n == 0 {
i.F.Close()
Ctxt.LineHist.Pop(int(Lineno))
goto pop
}
fi.P = i.B[1:n]
return int(i.B[0]) & 0xff
pop:
iostack = i.Link
i.Link = iofree
iofree = i
i = iostack
if i == nil {
return EOF
}
fi.P = i.P
if len(fi.P) == 0 {
goto loop
}
tmp8 := fi.P
fi.P = fi.P[1:]
return int(tmp8[0]) & 0xff
}
var last string
func Yyerror(a string, args ...interface{}) {
/*
* hack to intercept message from yaccpar
*/
if a == "syntax error" || len(args) == 1 && a == "%s" && args[0] == "syntax error" {
Yyerror("syntax error, last name: %s", last)
return
}
prfile(Lineno)
fmt.Printf("%s\n", fmt.Sprintf(a, args...))
nerrors++
if nerrors > 10 {
fmt.Printf("too many errors\n")
errorexit()
}
}
func prfile(l int32) {
obj.Linkprfile(Ctxt, int(l))
}
func GETC() int {
if len(fi.P) == 0 {
return filbuf()
}
c := int(fi.P[0])
fi.P = fi.P[1:]
return c
}
func isdigit(c int) bool {
return '0' <= c && c <= '9'
}
func strtoll(s string, p *byte, base int) int64 {
if p != nil {
panic("strtoll")
}
n, err := strconv.ParseInt(s, base, 64)
if err != nil {
return 0
}
return n
}
func atof(s string) float64 {
f, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0
}
return f
}
// Inferno utils/cc/macbody
// http://code.Google.Com/p/inferno-os/source/browse/utils/cc/macbody
//
// 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
import (
"bytes"
"fmt"
"os"
"strings"
)
const (
VARMAC = 0x80
)
func getnsn() int32 {
c := getnsc()
if c < '0' || c > '9' {
return -1
}
n := int32(0)
for c >= '0' && c <= '9' {
n = n*10 + int32(c) - '0'
c = getc()
}
unget(c)
return n
}
func getsym() *Sym {
c := getnsc()
if !isalpha(c) && c != '_' && c < 0x80 {
unget(c)
return nil
}
var buf bytes.Buffer
for {
buf.WriteByte(byte(c))
c = getc()
if isalnum(c) || c == '_' || c >= 0x80 {
continue
}
unget(c)
break
}
last = buf.String()
return Lookup(last)
}
func getsymdots(dots *int) *Sym {
s := getsym()
if s != nil {
return s
}
c := getnsc()
if c != '.' {
unget(c)
return nil
}
if getc() != '.' || getc() != '.' {
Yyerror("bad dots in macro")
}
*dots = 1
return Lookup("__VA_ARGS__")
}
func getcom() int {
var c int
for {
c = getnsc()
if c != '/' {
break
}
c = getc()
if c == '/' {
for c != '\n' {
c = getc()
}
break
}
if c != '*' {
break
}
c = getc()
for {
if c == '*' {
c = getc()
if c != '/' {
continue
}
c = getc()
break
}
if c == '\n' {
Yyerror("comment across newline")
break
}
c = getc()
}
if c == '\n' {
break
}
}
return c
}
func dodefine(cp string) {
var s *Sym
if i := strings.Index(cp, "="); i >= 0 {
p := cp[i+1:]
cp = cp[:i]
s = Lookup(cp)
s.Macro = &Macro{Text: p}
} else {
s = Lookup(cp)
s.Macro = &Macro{Text: "1"}
}
if debug['m'] != 0 {
fmt.Printf("#define (-D) %s %s\n", s.Name, s.Macro.Text)
}
}
var mactab = []struct {
Macname string
Macf func()
}{
{"ifdef", nil}, /* macif(0) */
{"ifndef", nil}, /* macif(1) */
{"else", nil}, /* macif(2) */
{"line", maclin},
{"define", macdef},
{"include", macinc},
{"undef", macund},
{"pragma", macprag},
{"endif", macend},
}
func domacro() {
s := getsym()
if s == nil {
s = Lookup("endif")
}
for i := 0; i < len(mactab); i++ {
if s.Name == mactab[i].Macname {
if mactab[i].Macf != nil {
mactab[i].Macf()
} else {
macif(i)
}
return
}
}
Yyerror("unknown #: %s", s.Name)
macend()
}
func macund() {
s := getsym()
macend()
if s == nil {
Yyerror("syntax in #undef")
return
}
s.Macro = nil
}
const (
NARG = 25
)
func macdef() {
var args [NARG]string
var n int
var i int
var c int
var dots int
var ischr int
var base bytes.Buffer
s := getsym()
if s == nil {
goto bad
}
if s.Macro != nil {
Yyerror("macro redefined: %s", s.Name)
}
c = getc()
n = -1
dots = 0
if c == '(' {
n++
c = getnsc()
if c != ')' {
unget(c)
var a *Sym
var c int
for {
a = getsymdots(&dots)
if a == nil {
goto bad
}
if n >= NARG {
Yyerror("too many arguments in #define: %s", s.Name)
goto bad
}
args[n] = a.Name
n++
c = getnsc()
if c == ')' {
break
}
if c != ',' || dots != 0 {
goto bad
}
}
}
c = getc()
}
if isspace(c) {
if c != '\n' {
c = getnsc()
}
}
ischr = 0
for {
if isalpha(c) || c == '_' {
var buf bytes.Buffer
buf.WriteByte(byte(c))
c = getc()
for isalnum(c) || c == '_' {
buf.WriteByte(byte(c))
c = getc()
}
symb := buf.String()
for i = 0; i < n; i++ {
if symb == args[i] {
break
}
}
if i >= n {
base.WriteString(symb)
continue
}
base.WriteByte('#')
base.WriteByte(byte('a' + i))
continue
}
if ischr != 0 {
if c == '\\' {
base.WriteByte(byte(c))
c = getc()
} else if c == ischr {
ischr = 0
}
} else {
if c == '"' || c == '\'' {
base.WriteByte(byte(c))
ischr = c
c = getc()
continue
}
if c == '/' {
c = getc()
if c == '/' {
c = getc()
for {
if c == '\n' {
break
}
c = getc()
}
continue
}
if c == '*' {
c = getc()
for {
if c == '*' {
c = getc()
if c != '/' {
continue
}
c = getc()
break
}
if c == '\n' {
Yyerror("comment and newline in define: %s", s.Name)
break
}
c = getc()
}
continue
}
base.WriteByte('/')
continue
}
}
if c == '\\' {
c = getc()
if c == '\n' {
c = getc()
continue
} else if c == '\r' {
c = getc()
if c == '\n' {
c = getc()
continue
}
}
base.WriteByte('\\')
continue
}
if c == '\n' {
break
}
if c == '#' {
if n > 0 {
base.WriteByte(byte(c))
}
}
base.WriteByte(byte(c))
c = GETC()
if c == '\n' {
Lineno++
}
if c == -1 {
Yyerror("eof in a macro: %s", s.Name)
break
}
}
s.Macro = &Macro{
Text: base.String(),
Narg: n + 1,
Dots: dots != 0,
}
if debug['m'] != 0 {
fmt.Printf("#define %s %s\n", s.Name, s.Macro.Text)
}
return
bad:
if s == nil {
Yyerror("syntax in #define")
} else {
Yyerror("syntax in #define: %s", s.Name)
}
macend()
}
func macexpand(s *Sym) []byte {
if s.Macro.Narg == 0 {
if debug['m'] != 0 {
fmt.Printf("#expand %s %s\n", s.Name, s.Macro.Text)
}
return []byte(s.Macro.Text)
}
nargs := s.Macro.Narg - 1
dots := s.Macro.Dots
c := getnsc()
var arg []string
var cp string
var out bytes.Buffer
if c != '(' {
goto bad
}
c = getc()
if c != ')' {
unget(c)
l := 0
var buf bytes.Buffer
var c int
for {
c = getc()
if c == '"' {
for {
buf.WriteByte(byte(c))
c = getc()
if c == '\\' {
buf.WriteByte(byte(c))
c = getc()
continue
}
if c == '\n' {
goto bad
}
if c == '"' {
break
}
}
}
if c == '\'' {
for {
buf.WriteByte(byte(c))
c = getc()
if c == '\\' {
buf.WriteByte(byte(c))
c = getc()
continue
}
if c == '\n' {
goto bad
}
if c == '\'' {
break
}
}
}
if c == '/' {
c = getc()
switch c {
case '*':
for {
c = getc()
if c == '*' {
c = getc()
if c == '/' {
break
}
}
}
buf.WriteByte(' ')
continue
case '/':
for {
c = getc()
if !(c != '\n') {
break
}
}
default:
unget(c)
c = '/'
}
}
if l == 0 {
if c == ',' {
if len(arg) == nargs-1 && dots {
buf.WriteByte(',')
continue
}
arg = append(arg, buf.String())
buf.Reset()
continue
}
if c == ')' {
arg = append(arg, buf.String())
break
}
}
if c == '\n' {
c = ' '
}
buf.WriteByte(byte(c))
if c == '(' {
l++
}
if c == ')' {
l--
}
}
}
if len(arg) != nargs {
Yyerror("argument mismatch expanding: %s", s.Name)
return nil
}
cp = s.Macro.Text
for i := 0; i < len(cp); i++ {
c = int(cp[i])
if c == '\n' {
c = ' '
}
if c != '#' {
out.WriteByte(byte(c))
continue
}
i++
if i >= len(cp) {
goto bad
}
c = int(cp[i])
if c == '#' {
out.WriteByte(byte(c))
continue
}
c -= 'a'
if c < 0 || c >= len(arg) {
continue
}
out.WriteString(arg[c])
}
if debug['m'] != 0 {
fmt.Printf("#expand %s %s\n", s.Name, out.String())
}
return out.Bytes()
bad:
Yyerror("syntax in macro expansion: %s", s.Name)
return nil
}
func macinc() {
var c int
var buf bytes.Buffer
var f *os.File
var hp string
var str string
var symb string
c0 := getnsc()
if c0 != '"' {
c = c0
if c0 != '<' {
goto bad
}
c0 = '>'
}
for {
c = getc()
if c == c0 {
break
}
if c == '\n' {
goto bad
}
buf.WriteByte(byte(c))
}
str = buf.String()
c = getcom()
if c != '\n' {
goto bad
}
for i := 0; i < len(include); i++ {
if i == 0 && c0 == '>' {
continue
}
symb = include[i]
symb += "/"
if symb == "./" {
symb = ""
}
symb += str
var err error
f, err = os.Open(symb)
if err == nil {
break
}
}
if f == nil {
symb = str
}
hp = symb
newio()
pushio()
newfile(hp, f)
return
bad:
unget(c)
Yyerror("syntax in #include")
macend()
}
func maclin() {
var buf bytes.Buffer
var symb string
n := getnsn()
c := getc()
if n < 0 {
goto bad
}
for {
if c == ' ' || c == '\t' {
c = getc()
continue
}
if c == '"' {
break
}
if c == '\n' {
symb = "<noname>"
goto nn
}
goto bad
}
for {
c = getc()
if c == '"' {
break
}
buf.WriteByte(byte(c))
}
symb = buf.String()
c = getcom()
if c != '\n' {
goto bad
}
nn:
Ctxt.LineHist.Update(int(Lineno), symb, int(n))
return
bad:
unget(c)
Yyerror("syntax in #line")
macend()
}
func macif(f int) {
var c int
var l int
var bol int
var s *Sym
if f == 2 {
goto skip
}
s = getsym()
if s == nil {
goto bad
}
if getcom() != '\n' {
goto bad
}
if (s.Macro != nil) != (f != 0) {
return
}
skip:
bol = 1
l = 0
for {
c = getc()
if c != '#' {
if !isspace(c) {
bol = 0
}
if c == '\n' {
bol = 1
}
continue
}
if !(bol != 0) {
continue
}
s = getsym()
if s == nil {
continue
}
if s.Name == "endif" {
if l != 0 {
l--
continue
}
macend()
return
}
if s.Name == "ifdef" || s.Name == "ifndef" {
l++
continue
}
if l == 0 && f != 2 && s.Name == "else" {
macend()
return
}
}
bad:
Yyerror("syntax in #if(n)def")
macend()
}
func macprag() {
var c int
s := getsym()
if s != nil && s.Name == "lib" {
c0 := getnsc()
if c0 != '"' {
c = c0
if c0 != '<' {
goto bad
}
c0 = '>'
}
var buf bytes.Buffer
for {
c = getc()
if c == c0 {
break
}
if c == '\n' {
goto bad
}
buf.WriteByte(byte(c))
}
symb := buf.String()
c = getcom()
if c != '\n' {
goto bad
}
/*
* put pragma-line in as a funny history
*/
Ctxt.AddImport(symb)
return
}
if s != nil && s.Name == "pack" {
pragpack()
return
}
if s != nil && s.Name == "fpround" {
pragfpround()
return
}
if s != nil && s.Name == "textflag" {
pragtextflag()
return
}
if s != nil && s.Name == "dataflag" {
pragdataflag()
return
}
if s != nil && s.Name == "varargck" {
pragvararg()
return
}
if s != nil && s.Name == "incomplete" {
pragincomplete()
return
}
if s != nil && (strings.HasPrefix(s.Name, "cgo_") || strings.HasPrefix(s.Name, "dyn")) {
pragcgo(s.Name)
return
}
for getnsc() != '\n' {
}
return
bad:
unget(c)
Yyerror("syntax in #pragma lib")
macend()
}
func macend() {
var c int
for {
c = getnsc()
if c < 0 || c == '\n' {
return
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment