blob: af63e4d9f6d3438fe894ea25fb0ffc9a50ffd1b3 [file] [log] [blame]
// $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 {
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;
}
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;
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();
}