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