blob: d8ec242400456df6939a5226cc0e21c8ad60d908 [file] [log] [blame]
// 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
const (
VARMAC = 0x80
)
func getnsn() int32 {
var n int32
var c int
c = getnsc()
if c < '0' || c > '9' {
return -1
}
n = 0
for c >= '0' && c <= '9' {
n = n*10 + int32(c) - '0'
c = getc()
}
unget(c)
return n
}
func getsym() *new5a.Sym {
var c int
var cp string
c = getnsc()
if !(main.Isalpha(c) != 0) && c != '_' && c < 0x80 {
unget(c)
return nil
}
for cp = new5a.Symb; ; {
if cp <= new5a.Symb[new5a.NSYMB-4:] {
cp[0] = byte(c)
cp = cp[1:]
}
c = getc()
if main.Isalnum(c) != 0 || c == '_' || c >= 0x80 {
continue
}
unget(c)
break
}
cp = ""
if cp > new5a.Symb[new5a.NSYMB-4:] {
Yyerror("symbol too large: %s", new5a.Symb)
}
return lookup()
}
func getsymdots(dots *int) *new5a.Sym {
var c int
var s *new5a.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 Slookup("__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 *new5a.Sym
var p string
var l int32
Ensuresymb(int32(len(cp)))
new5a.Symb = cp
p = main.Strchr(new5a.Symb, '=')
if p != "" {
p = ""
p = p[1:]
s = lookup()
l = int32(len(p)) + 2 /* +1 null, +1 nargs */
s.Macro = Alloc(l).(string)
s.Macro[1:] = p
} else {
s = lookup()
s.Macro = "\0001" /* \000 is nargs */
}
if new5a.Debug['m'] != 0 {
fmt.Printf("#define (-D) %s %s\n", s.Name, s.Macro[1:])
}
}
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() {
var i int
var s *new5a.Sym
s = getsym()
if s == nil {
s = Slookup("endif")
}
for i = 0; mactab[i].macname != ""; 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() {
var s *new5a.Sym
s = getsym()
macend()
if s == nil {
Yyerror("syntax in #undef")
return
}
s.Macro = ""
}
const (
NARG = 25
)
func macdef() {
var s *new5a.Sym
var a *new5a.Sym
var args [NARG]string
var np string
var base string
var n int
var i int
var c int
var len int
var dots int
var ischr int
s = getsym()
if s == nil {
goto bad
}
if s.Macro != "" {
Yyerror("macro redefined: %s", s.Name)
}
c = getc()
n = -1
dots = 0
if c == '(' {
n++
c = getnsc()
if c != ')' {
unget(c)
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 main.Isspace(c) != 0 {
if c != '\n' {
c = getnsc()
}
}
base = new5a.Hunk
len = 1
ischr = 0
for {
if main.Isalpha(c) != 0 || c == '_' {
np = new5a.Symb
np[0] = byte(c)
np = np[1:]
c = getc()
for main.Isalnum(c) != 0 || c == '_' {
np[0] = byte(c)
np = np[1:]
c = getc()
}
np = ""
for i = 0; i < n; i++ {
if new5a.Symb == args[i] {
break
}
}
if i >= n {
i = len(new5a.Symb)
base = Allocn(base, int32(len), int32(i)).(string)
main.Memmove(base[len:], new5a.Symb, i)
len += i
continue
}
base = Allocn(base, int32(len), 2).(string)
base[len] = '#'
len++
base[len] = byte('a' + i)
len++
continue
}
if ischr != 0 {
if c == '\\' {
base = Allocn(base, int32(len), 1).(string)
base[len] = byte(c)
len++
c = getc()
} else if c == ischr {
ischr = 0
}
} else {
if c == '"' || c == '\'' {
base = Allocn(base, int32(len), 1).(string)
base[len] = byte(c)
len++
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 = Allocn(base, int32(len), 1).(string)
base[len] = '/'
len++
continue
}
}
if c == '\\' {
c = getc()
if c == '\n' {
c = getc()
continue
} else if c == '\r' {
c = getc()
if c == '\n' {
c = getc()
continue
}
}
base = Allocn(base, int32(len), 1).(string)
base[len] = '\\'
len++
continue
}
if c == '\n' {
break
}
if c == '#' {
if n > 0 {
base = Allocn(base, int32(len), 1).(string)
base[len] = byte(c)
len++
}
}
base = Allocn(base, int32(len), 1).(string)
base[len] = byte(c)
len++
new5a.Fi.c--
var tmp C.int
if new5a.Fi.c < 0 {
tmp = C.int(filbuf())
} else {
tmp = new5a.Fi.p[0] & 0xff
}
c = int(tmp)
if c == '\n' {
new5a.Lineno++
}
if c == -1 {
Yyerror("eof in a macro: %s", s.Name)
break
}
}
for {
base = Allocn(base, int32(len), 1).(string)
base[len] = 0
len++
if !(len&3 != 0 /*untyped*/) {
break
}
}
base[0] = byte(n + 1)
if dots != 0 {
base[0] |= VARMAC
}
s.Macro = base
if new5a.Debug['m'] != 0 {
fmt.Printf("#define %s %s\n", s.Name, s.Macro[1:])
}
return
bad:
if s == nil {
Yyerror("syntax in #define")
} else {
Yyerror("syntax in #define: %s", s.Name)
}
macend()
}
func macexpand(s *new5a.Sym, b string) {
var buf string
var n int
var l int
var c int
var nargs int
var arg [NARG]string
var cp string
var ob string
var ecp string
var dots int8
ob = b
if s.Macro[0] == 0 {
b = s.Macro[1:]
if new5a.Debug['m'] != 0 {
fmt.Printf("#expand %s %s\n", s.Name, ob)
}
return
}
nargs = int(int8(s.Macro[0]&^VARMAC)) - 1
dots = int8(s.Macro[0] & VARMAC)
c = getnsc()
if c != '(' {
goto bad
}
n = 0
c = getc()
if c != ')' {
unget(c)
l = 0
cp = buf
ecp = cp[sizeof(buf)-4:]
arg[n] = cp
n++
for {
if cp >= ecp {
goto toobig
}
c = getc()
if c == '"' {
for {
if cp >= ecp {
goto toobig
}
cp[0] = byte(c)
cp = cp[1:]
c = getc()
if c == '\\' {
cp[0] = byte(c)
cp = cp[1:]
c = getc()
continue
}
if c == '\n' {
goto bad
}
if c == '"' {
break
}
}
}
if c == '\'' {
for {
if cp >= ecp {
goto toobig
}
cp[0] = byte(c)
cp = cp[1:]
c = getc()
if c == '\\' {
cp[0] = byte(c)
cp = cp[1:]
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
}
}
}
cp[0] = ' '
cp = cp[1:]
continue
case '/':
for {
c = getc()
if !(c != '\n') {
break
}
}
default:
unget(c)
c = '/'
}
}
if l == 0 {
if c == ',' {
if n == nargs && dots != 0 {
cp[0] = ','
cp = cp[1:]
continue
}
cp = ""
cp = cp[1:]
arg[n] = cp
n++
if n > nargs {
break
}
continue
}
if c == ')' {
break
}
}
if c == '\n' {
c = ' '
}
cp[0] = byte(c)
cp = cp[1:]
if c == '(' {
l++
}
if c == ')' {
l--
}
}
cp = ""
}
if n != nargs {
Yyerror("argument mismatch expanding: %s", s.Name)
b = ""
return
}
cp = s.Macro[1:]
for {
c = int(cp[0])
cp = cp[1:]
if c == '\n' {
c = ' '
}
if c != '#' {
b[0] = byte(c)
b = b[1:]
if c == 0 {
break
}
continue
}
c = int(cp[0])
cp = cp[1:]
if c == 0 {
goto bad
}
if c == '#' {
b[0] = byte(c)
b = b[1:]
continue
}
c -= 'a'
if c < 0 || c >= n {
continue
}
b = arg[c]
b = b[len(arg[c]):]
}
b = ""
if new5a.Debug['m'] != 0 {
fmt.Printf("#expand %s %s\n", s.Name, ob)
}
return
bad:
Yyerror("syntax in macro expansion: %s", s.Name)
b = ""
return
toobig:
Yyerror("too much text in macro expansion: %s", s.Name)
b = ""
}
func macinc() {
var c0 int
var c int
var i int
var f int
var str string
var hp string
c0 = getnsc()
if c0 != '"' {
c = c0
if c0 != '<' {
goto bad
}
c0 = '>'
}
for hp = str; ; {
c = getc()
if c == c0 {
break
}
if c == '\n' {
goto bad
}
hp[0] = byte(c)
hp = hp[1:]
}
hp = ""
c = getcom()
if c != '\n' {
goto bad
}
f = -1
for i = 0; i < new5a.Ninclude; i++ {
if i == 0 && c0 == '>' {
continue
}
Ensuresymb(int32(len(new5a.Include[i])) + int32(len(str)) + 2)
new5a.Symb = new5a.Include[i]
new5a.Symb += "/"
if new5a.Symb == "./" {
new5a.Symb = ""
}
new5a.Symb += str
f = main.Open(new5a.Symb, main.OREAD)
if f >= 0 {
break
}
}
if f < 0 {
new5a.Symb = str
}
c = len(new5a.Symb) + 1
hp = Alloc(int32(c)).(string)
main.Memmove(hp, new5a.Symb, c)
newio()
pushio()
newfile(hp, f)
return
bad:
unget(c)
Yyerror("syntax in #include")
macend()
}
func maclin() {
var cp string
var c int
var n int32
n = getnsn()
c = getc()
if n < 0 {
goto bad
}
for {
if c == ' ' || c == '\t' {
c = getc()
continue
}
if c == '"' {
break
}
if c == '\n' {
new5a.Symb = "<noname>"
goto nn
}
goto bad
}
cp = new5a.Symb
for {
c = getc()
if c == '"' {
break
}
cp[0] = byte(c)
cp = cp[1:]
}
cp = ""
c = getcom()
if c != '\n' {
goto bad
}
nn:
c = len(new5a.Symb) + 1
cp = Alloc(int32(c)).(string)
main.Memmove(cp, new5a.Symb, c)
obj.Linklinehist(new5a.Ctxt, int(new5a.Lineno), cp, 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 *new5a.Sym
if f == 2 {
goto skip
}
s = getsym()
if s == nil {
goto bad
}
if getcom() != '\n' {
goto bad
}
if (s.Macro != "")^f != 0 /*untyped*/ {
return
}
skip:
bol = 1
l = 0
for {
c = getc()
if c != '#' {
if !(main.Isspace(c) != 0) {
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 s *new5a.Sym
var c0 int
var c int
var hp string
s = getsym()
if s != nil && s.Name == "lib" {
goto praglib
}
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
praglib:
c0 = getnsc()
if c0 != '"' {
c = c0
if c0 != '<' {
goto bad
}
c0 = '>'
}
for hp = new5a.Symb; ; {
c = getc()
if c == c0 {
break
}
if c == '\n' {
goto bad
}
hp[0] = byte(c)
hp = hp[1:]
}
hp = ""
c = getcom()
if c != '\n' {
goto bad
}
/*
* put pragma-line in as a funny history
*/
c = len(new5a.Symb) + 1
hp = Alloc(int32(c)).(string)
main.Memmove(hp, new5a.Symb, c)
obj.Linklinehist(new5a.Ctxt, int(new5a.Lineno), hp, -1)
return
bad:
unget(c)
Yyerror("syntax in #pragma lib")
macend()
}
func macend() {
var c int
for {
c = getnsc()
if c < 0 || c == '\n' {
return
}
}
}