|  | // run | 
|  |  | 
|  | // 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. | 
|  |  | 
|  | // Test general operation using s-list. | 
|  | // First Go program ever run (although not in this exact form). | 
|  |  | 
|  | 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() | 
|  | } |