You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
4.3 KiB
281 lines
4.3 KiB
4 months ago
|
// 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()
|
||
|
}
|