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 10 package main 11 12 import "fmt" 13 14 const nilchar = 0 15 16 type Atom struct { 17 str string 18 integer int 19 next *Slist /* in hash bucket */ 20 } 21 22 type List struct { 23 car *Slist 24 cdr *Slist 25 } 26 27 type Slist struct { 28 isatom bool 29 isstring bool 30 //union { 31 atom Atom 32 list List 33 //} u; 34 35 } 36 37 func (this *Slist) Car() *Slist { 38 return this.list.car 39 } 40 41 func (this *Slist) Cdr() *Slist { 42 return this.list.cdr 43 } 44 45 func (this *Slist) String() string { 46 return this.atom.str 47 } 48 49 func (this *Slist) Integer() int { 50 return this.atom.integer 51 } 52 53 func (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 68 var token int 69 var peekc int = -1 70 var lineno int32 = 1 71 72 var input string 73 var inputindex int = 0 74 var tokenbuf [100]byte 75 var tokenlen int = 0 76 77 const EOF int = -1 78 79 func 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 97 func (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 124 func (slist *Slist) Print() string { 125 return slist.PrintOne(true) 126 } 127 128 func 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 148 func WhiteSpace(c int) bool { 149 return c == ' ' || c == '\t' || c == '\r' || c == '\n' 150 } 151 152 func 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 192 func 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 201 func 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 222 func 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 237 func 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 245 func 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 275 func OpenFile() { 276 input = "(defn foo (add 12 34))\n\x00" 277 inputindex = 0 278 peekc = -1 // BUG 279 NextToken() 280 } 281