| // $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 | |
| 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) Print(); | |
| 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); | |
| } | |
| func OpenFile(); | |
| func Parse() *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; | |
| } | |
| list.Print(); | |
| list.Free(); | |
| break; | |
| } | |
| } | |
| func (slist *Slist) PrintOne(doparen bool) | |
| { | |
| if slist == nil { | |
| return; | |
| } | |
| if slist.isatom { | |
| if slist.isstring { | |
| print(slist.String()); | |
| } else { | |
| print(slist.Integer()); | |
| } | |
| } else { | |
| if doparen { | |
| print("(" ); | |
| } | |
| slist.Car().PrintOne(true); | |
| if slist.Cdr() != nil { | |
| print(" "); | |
| slist.Cdr().PrintOne(false); | |
| } | |
| if doparen { | |
| print(")"); | |
| } | |
| } | |
| } | |
| func (slist *Slist) Print() | |
| { | |
| slist.PrintOne(true); | |
| print("\n"); | |
| } | |
| func Get() int | |
| { | |
| var c int; | |
| if peekc >= 0 { | |
| c = peekc; | |
| peekc = -1; | |
| } else { | |
| c = convert(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; | |
| var backslash bool; | |
| 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] = convert(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 h, length int; | |
| var slist, tail *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 + convert(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(); | |
| } |