blob: 4b4410ee859fc8bfa95ba388e84a7e1d398282ed [file] [log] [blame]
// 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()
}