1// run 2 3// Copyright 2009 The Go Authors. All rights reserved. 4// Use of this source code is governed by a BSD-style 5// license that can be found in the LICENSE file. 6 7// Test general operation using s-list. 8// First Go program ever run (although not in this exact form). 9 10package main 11 12import "fmt" 13 14const nilchar = 0 15 16type Atom struct { 17 str string 18 integer int 19 next *Slist /* in hash bucket */ 20} 21 22type List struct { 23 car *Slist 24 cdr *Slist 25} 26 27type Slist struct { 28 isatom bool 29 isstring bool 30 //union { 31 atom Atom 32 list List 33 //} u; 34 35} 36 37func (this *Slist) Car() *Slist { 38 return this.list.car 39} 40 41func (this *Slist) Cdr() *Slist { 42 return this.list.cdr 43} 44 45func (this *Slist) String() string { 46 return this.atom.str 47} 48 49func (this *Slist) Integer() int { 50 return this.atom.integer 51} 52 53func (slist *Slist) Free() { 54 if slist == nil { 55 return 56 } 57 if slist.isatom { 58 // free(slist.String()); 59 } else { 60 slist.Car().Free() 61 slist.Cdr().Free() 62 } 63 // free(slist); 64} 65 66//Slist* atom(byte *s, int i); 67 68var token int 69var peekc int = -1 70var lineno int32 = 1 71 72var input string 73var inputindex int = 0 74var tokenbuf [100]byte 75var tokenlen int = 0 76 77const EOF int = -1 78 79func main() { 80 var list *Slist 81 82 OpenFile() 83 for { 84 list = Parse() 85 if list == nil { 86 break 87 } 88 r := list.Print() 89 list.Free() 90 if r != "(defn foo (add 12 34))" { 91 panic(r) 92 } 93 break 94 } 95} 96 97func (slist *Slist) PrintOne(doparen bool) string { 98 if slist == nil { 99 return "" 100 } 101 var r string 102 if slist.isatom { 103 if slist.isstring { 104 r = slist.String() 105 } else { 106 r = fmt.Sprintf("%v", slist.Integer()) 107 } 108 } else { 109 if doparen { 110 r += "(" 111 } 112 r += slist.Car().PrintOne(true) 113 if slist.Cdr() != nil { 114 r += " " 115 r += slist.Cdr().PrintOne(false) 116 } 117 if doparen { 118 r += ")" 119 } 120 } 121 return r 122} 123 124func (slist *Slist) Print() string { 125 return slist.PrintOne(true) 126} 127 128func Get() int { 129 var c int 130 131 if peekc >= 0 { 132 c = peekc 133 peekc = -1 134 } else { 135 c = int(input[inputindex]) 136 inputindex++ 137 if c == '\n' { 138 lineno = lineno + 1 139 } 140 if c == nilchar { 141 inputindex = inputindex - 1 142 c = EOF 143 } 144 } 145 return c 146} 147 148func WhiteSpace(c int) bool { 149 return c == ' ' || c == '\t' || c == '\r' || c == '\n' 150} 151 152func NextToken() { 153 var i, c int 154 155 tokenbuf[0] = nilchar // clear previous token 156 c = Get() 157 for WhiteSpace(c) { 158 c = Get() 159 } 160 switch c { 161 case EOF: 162 token = EOF 163 case '(', ')': 164 token = c 165 break 166 default: 167 for i = 0; i < 100-1; { // sizeof tokenbuf - 1 168 tokenbuf[i] = byte(c) 169 i = i + 1 170 c = Get() 171 if c == EOF { 172 break 173 } 174 if WhiteSpace(c) || c == ')' { 175 peekc = c 176 break 177 } 178 } 179 if i >= 100-1 { // sizeof tokenbuf - 1 180 panic("atom too long\n") 181 } 182 tokenlen = i 183 tokenbuf[i] = nilchar 184 if '0' <= tokenbuf[0] && tokenbuf[0] <= '9' { 185 token = '0' 186 } else { 187 token = 'A' 188 } 189 } 190} 191 192func Expect(c int) { 193 if token != c { 194 print("parse error: expected ", c, "\n") 195 panic("parse") 196 } 197 NextToken() 198} 199 200// Parse a non-parenthesized list up to a closing paren or EOF 201func ParseList() *Slist { 202 var slist, retval *Slist 203 204 slist = new(Slist) 205 slist.list.car = nil 206 slist.list.cdr = nil 207 slist.isatom = false 208 slist.isstring = false 209 210 retval = slist 211 for { 212 slist.list.car = Parse() 213 if token == ')' || token == EOF { // empty cdr 214 break 215 } 216 slist.list.cdr = new(Slist) 217 slist = slist.list.cdr 218 } 219 return retval 220} 221 222func atom(i int) *Slist { // BUG: uses tokenbuf; should take argument) 223 var slist *Slist 224 225 slist = new(Slist) 226 if token == '0' { 227 slist.atom.integer = i 228 slist.isstring = false 229 } else { 230 slist.atom.str = string(tokenbuf[0:tokenlen]) 231 slist.isstring = true 232 } 233 slist.isatom = true 234 return slist 235} 236 237func atoi() int { // BUG: uses tokenbuf; should take argument) 238 var v int = 0 239 for i := 0; i < tokenlen && '0' <= tokenbuf[i] && tokenbuf[i] <= '9'; i = i + 1 { 240 v = 10*v + int(tokenbuf[i]-'0') 241 } 242 return v 243} 244 245func Parse() *Slist { 246 var slist *Slist 247 248 if token == EOF || token == ')' { 249 return nil 250 } 251 if token == '(' { 252 NextToken() 253 slist = ParseList() 254 Expect(')') 255 return slist 256 } else { 257 // Atom 258 switch token { 259 case EOF: 260 return nil 261 case '0': 262 slist = atom(atoi()) 263 case '"', 'A': 264 slist = atom(0) 265 default: 266 slist = nil 267 print("unknown token: ", token, "\n") 268 } 269 NextToken() 270 return slist 271 } 272 return nil 273} 274 275func OpenFile() { 276 input = "(defn foo (add 12 34))\n\x00" 277 inputindex = 0 278 peekc = -1 // BUG 279 NextToken() 280} 281