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