| // $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) 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; |
| } |
| 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 = 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(); |
| } |