| // $G $D/$F.go && $L $F.$A && ./$A.out |
| |
| // 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. |
| |
| package main |
| |
| import "fmt" |
| |
| const nilchar = 0 |
| |
| type Atom struct { |
| str string |
| integer int |
| next *Slist /* in hash bucket */ |
| } |
| |
| type List struct { |
| car *Slist |
| cdr *Slist |
| } |
| |
| type Slist struct { |
| isatom bool |
| isstring bool |
| //union { |
| atom Atom |
| list List |
| //} u; |
| |
| } |
| |
| func (this *Slist) Car() *Slist { |
| return this.list.car |
| } |
| |
| func (this *Slist) Cdr() *Slist { |
| return this.list.cdr |
| } |
| |
| func (this *Slist) String() string { |
| return this.atom.str |
| } |
| |
| func (this *Slist) Integer() int { |
| return this.atom.integer |
| } |
| |
| func (slist *Slist) Free() { |
| if slist == nil { |
| return |
| } |
| if slist.isatom { |
| // free(slist.String()); |
| } else { |
| slist.Car().Free() |
| slist.Cdr().Free() |
| } |
| // free(slist); |
| } |
| |
| //Slist* atom(byte *s, int i); |
| |
| var token int |
| var peekc int = -1 |
| var lineno int32 = 1 |
| |
| var input string |
| var inputindex int = 0 |
| var tokenbuf [100]byte |
| var tokenlen int = 0 |
| |
| const EOF int = -1 |
| |
| func main() { |
| var list *Slist |
| |
| OpenFile() |
| for { |
| list = Parse() |
| if list == nil { |
| break |
| } |
| r := list.Print() |
| list.Free() |
| if r != "(defn foo (add 12 34))" { |
| panic(r) |
| } |
| break |
| } |
| } |
| |
| func (slist *Slist) PrintOne(doparen bool) string { |
| if slist == nil { |
| return "" |
| } |
| var r string |
| if slist.isatom { |
| if slist.isstring { |
| r = slist.String() |
| } else { |
| r = fmt.Sprintf("%v", slist.Integer()) |
| } |
| } else { |
| if doparen { |
| r += "(" |
| } |
| r += slist.Car().PrintOne(true) |
| if slist.Cdr() != nil { |
| r += " " |
| r += slist.Cdr().PrintOne(false) |
| } |
| if doparen { |
| r += ")" |
| } |
| } |
| return r |
| } |
| |
| func (slist *Slist) Print() string { |
| return slist.PrintOne(true) |
| } |
| |
| func Get() int { |
| var c int |
| |
| if peekc >= 0 { |
| c = peekc |
| peekc = -1 |
| } else { |
| c = int(input[inputindex]) |
| inputindex++ |
| if c == '\n' { |
| lineno = lineno + 1 |
| } |
| if c == nilchar { |
| inputindex = inputindex - 1 |
| c = EOF |
| } |
| } |
| return c |
| } |
| |
| func WhiteSpace(c int) bool { |
| return c == ' ' || c == '\t' || c == '\r' || c == '\n' |
| } |
| |
| func NextToken() { |
| var i, c int |
| |
| tokenbuf[0] = nilchar // clear previous token |
| c = Get() |
| for WhiteSpace(c) { |
| c = Get() |
| } |
| switch c { |
| case EOF: |
| token = EOF |
| case '(', ')': |
| token = c |
| break |
| default: |
| for i = 0; i < 100-1; { // sizeof tokenbuf - 1 |
| tokenbuf[i] = byte(c) |
| i = i + 1 |
| c = Get() |
| if c == EOF { |
| break |
| } |
| if WhiteSpace(c) || c == ')' { |
| peekc = c |
| break |
| } |
| } |
| if i >= 100-1 { // sizeof tokenbuf - 1 |
| panic("atom too long\n") |
| } |
| tokenlen = i |
| tokenbuf[i] = nilchar |
| if '0' <= tokenbuf[0] && tokenbuf[0] <= '9' { |
| token = '0' |
| } else { |
| token = 'A' |
| } |
| } |
| } |
| |
| func Expect(c int) { |
| if token != c { |
| print("parse error: expected ", c, "\n") |
| panic("parse") |
| } |
| NextToken() |
| } |
| |
| // Parse a non-parenthesized list up to a closing paren or EOF |
| func ParseList() *Slist { |
| var slist, retval *Slist |
| |
| slist = new(Slist) |
| slist.list.car = nil |
| slist.list.cdr = nil |
| slist.isatom = false |
| slist.isstring = false |
| |
| retval = slist |
| for { |
| slist.list.car = Parse() |
| if token == ')' || token == EOF { // empty cdr |
| break |
| } |
| slist.list.cdr = new(Slist) |
| slist = slist.list.cdr |
| } |
| return retval |
| } |
| |
| func atom(i int) *Slist { // BUG: uses tokenbuf; should take argument) |
| var slist *Slist |
| |
| slist = new(Slist) |
| if token == '0' { |
| slist.atom.integer = i |
| slist.isstring = false |
| } else { |
| slist.atom.str = string(tokenbuf[0:tokenlen]) |
| slist.isstring = true |
| } |
| slist.isatom = true |
| return slist |
| } |
| |
| func atoi() int { // BUG: uses tokenbuf; should take argument) |
| var v int = 0 |
| for i := 0; i < tokenlen && '0' <= tokenbuf[i] && tokenbuf[i] <= '9'; i = i + 1 { |
| v = 10*v + int(tokenbuf[i]-'0') |
| } |
| return v |
| } |
| |
| func Parse() *Slist { |
| var slist *Slist |
| |
| if token == EOF || token == ')' { |
| return nil |
| } |
| if token == '(' { |
| NextToken() |
| slist = ParseList() |
| Expect(')') |
| return slist |
| } else { |
| // Atom |
| switch token { |
| case EOF: |
| return nil |
| case '0': |
| slist = atom(atoi()) |
| case '"', 'A': |
| slist = atom(0) |
| default: |
| slist = nil |
| print("unknown token: ", token, "\n") |
| } |
| NextToken() |
| return slist |
| } |
| return nil |
| } |
| |
| func OpenFile() { |
| input = "(defn foo (add 12 34))\n\x00" |
| inputindex = 0 |
| peekc = -1 // BUG |
| NextToken() |
| } |