mirror of
https://github.com/golang/go
synced 2024-09-04 23:44:16 +00:00
287 lines
4.3 KiB
Go
287 lines
4.3 KiB
Go
// $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;
|
|
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();
|
|
}
|