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