// $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; List struct; Slist struct; ) 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) Print(); 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); } func OpenFile(); func Parse() *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; var backslash bool; 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 h, length int; var slist, tail *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(); }