Home | History | Annotate | Download | only in ken
      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 
     10 package main
     11 
     12 import "fmt"
     13 
     14 const nilchar = 0
     15 
     16 type Atom struct {
     17 	str     string
     18 	integer int
     19 	next    *Slist /* in hash bucket */
     20 }
     21 
     22 type List struct {
     23 	car *Slist
     24 	cdr *Slist
     25 }
     26 
     27 type Slist struct {
     28 	isatom   bool
     29 	isstring bool
     30 	//union {
     31 	atom Atom
     32 	list List
     33 	//} u;
     34 
     35 }
     36 
     37 func (this *Slist) Car() *Slist {
     38 	return this.list.car
     39 }
     40 
     41 func (this *Slist) Cdr() *Slist {
     42 	return this.list.cdr
     43 }
     44 
     45 func (this *Slist) String() string {
     46 	return this.atom.str
     47 }
     48 
     49 func (this *Slist) Integer() int {
     50 	return this.atom.integer
     51 }
     52 
     53 func (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 
     68 var token int
     69 var peekc int = -1
     70 var lineno int32 = 1
     71 
     72 var input string
     73 var inputindex int = 0
     74 var tokenbuf [100]byte
     75 var tokenlen int = 0
     76 
     77 const EOF int = -1
     78 
     79 func 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 
     97 func (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 
    124 func (slist *Slist) Print() string {
    125 	return slist.PrintOne(true)
    126 }
    127 
    128 func 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 
    148 func WhiteSpace(c int) bool {
    149 	return c == ' ' || c == '\t' || c == '\r' || c == '\n'
    150 }
    151 
    152 func 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 
    192 func 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
    201 func 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 
    222 func 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 
    237 func 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 
    245 func 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 
    275 func OpenFile() {
    276 	input = "(defn foo (add 12 34))\n\x00"
    277 	inputindex = 0
    278 	peekc = -1 // BUG
    279 	NextToken()
    280 }
    281