Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(352)

Side by Side Diff: src/cmd/yacc/units.y

Issue 13283045: code review 13283045: cmd/yacc: replace units example with simpler expr example (Closed)
Patch Set: diff -r ef73acc06701 https://code.google.com/p/go Created 11 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« src/cmd/yacc/expr.y ('K') | « src/cmd/yacc/units.txt ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Derived from Plan 9's /sys/src/cmd/units.y
2 // http://plan9.bell-labs.com/sources/plan9/sys/src/cmd/units.y
3 //
4 // Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
5 // Portions Copyright 2009 The Go Authors. All Rights Reserved.
6 // Distributed under the terms of the Lucent Public License Version 1.02
7 // See http://plan9.bell-labs.com/plan9/license.html
8
9 // Generate parser with prefix "units_":
10 // go tool yacc -p "units_"
11
12 %{
13
14 // This tag will end up in the generated y.go, so that forgetting
15 // 'make clean' does not fail the next build.
16
17 // +build ignore
18
19 // units.y
20 // example of a Go yacc program
21 // usage is
22 // go tool yacc -p "units_" units.y (produces y.go)
23 // go build -o units y.go
24 // ./units $GOROOT/src/cmd/yacc/units.txt
25 // you have: c
26 // you want: furlongs/fortnight
27 // * 1.8026178e+12
28 // / 5.5474878e-13
29 // you have:
30
31 package main
32
33 import (
34 "bufio"
35 "flag"
36 "fmt"
37 "math"
38 "runtime"
39 "os"
40 "path/filepath"
41 "strconv"
42 "unicode/utf8"
43 )
44
45 const (
46 Ndim = 15 // number of dimensions
47 Maxe = 695 // log of largest number
48 )
49
50 type Node struct {
51 vval float64
52 dim [Ndim]int8
53 }
54
55 type Var struct {
56 name string
57 node Node
58 }
59
60 var fi *bufio.Reader // input
61 var fund [Ndim]*Var // names of fundamental units
62 var line string // current input line
63 var lineno int // current input line number
64 var linep int // index to next rune in unput
65 var nerrors int // error count
66 var one Node // constant one
67 var peekrune rune // backup runt from input
68 var retnode1 Node
69 var retnode2 Node
70 var retnode Node
71 var sym string
72 var vflag bool
73 %}
74
75 %union {
76 node Node
77 vvar *Var
78 numb int
79 vval float64
80 }
81
82 %type <node> prog expr expr0 expr1 expr2 expr3 expr4
83
84 %token <vval> VÄL // dieresis to test UTF-8
85 %token <vvar> VAR
86 %token <numb> _SUP // tests leading underscore in token name
87 %%
88 prog:
89 ':' VAR expr
90 {
91 var f int
92 f = int($2.node.dim[0])
93 $2.node = $3
94 $2.node.dim[0] = 1
95 if f != 0 {
96 Errorf("redefinition of %v", $2.name)
97 } else if vflag {
98 fmt.Printf("%v\t%v\n", $2.name, &$2.node)
99 }
100 }
101 | ':' VAR '#'
102 {
103 var f, i int
104 for i = 1; i < Ndim; i++ {
105 if fund[i] == nil {
106 break
107 }
108 }
109 if i >= Ndim {
110 Error("too many dimensions")
111 i = Ndim - 1
112 }
113 fund[i] = $2
114 f = int($2.node.dim[0])
115 $2.node = one
116 $2.node.dim[0] = 1
117 $2.node.dim[i] = 1
118 if f != 0 {
119 Errorf("redefinition of %v", $2.name)
120 } else if vflag {
121 fmt.Printf("%v\t#\n", $2.name)
122 }
123 }
124 | ':'
125 {
126 }
127 | '?' expr
128 {
129 retnode1 = $2
130 }
131 | '?'
132 {
133 retnode1 = one
134 }
135
136 expr:
137 expr4
138 | expr '+' expr4
139 {
140 add(&$$, &$1, &$3)
141 }
142 | expr '-' expr4
143 {
144 sub(&$$, &$1, &$3)
145 }
146
147 expr4:
148 expr3
149 | expr4 '*' expr3
150 {
151 mul(&$$, &$1, &$3)
152 }
153 | expr4 '/' expr3
154 {
155 div(&$$, &$1, &$3)
156 }
157
158 expr3:
159 expr2
160 | expr3 expr2
161 {
162 mul(&$$, &$1, &$2)
163 }
164
165 expr2:
166 expr1
167 | expr2 _SUP
168 {
169 xpn(&$$, &$1, $2)
170 }
171 | expr2 '^' expr1
172 {
173 var i int
174 for i = 1; i < Ndim; i++ {
175 if $3.dim[i] != 0 {
176 Error("exponent has units")
177 $$ = $1
178 break
179 }
180 }
181 if i >= Ndim {
182 i = int($3.vval)
183 if float64(i) != $3.vval {
184 Error("exponent not integral")
185 }
186 xpn(&$$, &$1, i)
187 }
188 }
189
190 expr1:
191 expr0
192 | expr1 '|' expr0
193 {
194 div(&$$, &$1, &$3)
195 }
196
197 expr0:
198 VAR
199 {
200 if $1.node.dim[0] == 0 {
201 Errorf("undefined %v", $1.name)
202 $$ = one
203 } else {
204 $$ = $1.node
205 }
206 }
207 | VÄL
208 {
209 $$ = one
210 $$.vval = $1
211 }
212 | '(' expr ')'
213 {
214 $$ = $2
215 }
216 %%
217
218 type UnitsLex int
219
220 func (UnitsLex) Lex(yylval *units_SymType) int {
221 var c rune
222 var i int
223
224 c = peekrune
225 peekrune = ' '
226
227 loop:
228 if (c >= '0' && c <= '9') || c == '.' {
229 goto numb
230 }
231 if ralpha(c) {
232 goto alpha
233 }
234 switch c {
235 case ' ', '\t':
236 c = getrune()
237 goto loop
238 case '×':
239 return '*'
240 case '÷':
241 return '/'
242 case '¹', 'ⁱ':
243 yylval.numb = 1
244 return _SUP
245 case '²', '⁲':
246 yylval.numb = 2
247 return _SUP
248 case '³', '⁳':
249 yylval.numb = 3
250 return _SUP
251 }
252 return int(c)
253
254 alpha:
255 sym = ""
256 for i = 0; ; i++ {
257 sym += string(c)
258 c = getrune()
259 if !ralpha(c) {
260 break
261 }
262 }
263 peekrune = c
264 yylval.vvar = lookup(0)
265 return VAR
266
267 numb:
268 sym = ""
269 for i = 0; ; i++ {
270 sym += string(c)
271 c = getrune()
272 if !rdigit(c) {
273 break
274 }
275 }
276 peekrune = c
277 f, err := strconv.ParseFloat(sym, 64)
278 if err != nil {
279 fmt.Printf("error converting %v\n", sym)
280 f = 0
281 }
282 yylval.vval = f
283 return VÄL
284 }
285
286 func (UnitsLex) Error(s string) {
287 Errorf("syntax error, last name: %v", sym)
288 }
289
290 func main() {
291 var file string
292
293 flag.BoolVar(&vflag, "v", false, "verbose")
294
295 flag.Parse()
296
297 file = filepath.Join(runtime.GOROOT(), "src/cmd/yacc/units.txt")
298 if flag.NArg() > 0 {
299 file = flag.Arg(0)
300 } else if file == "" {
301 fmt.Fprintf(os.Stderr, "cannot find data file units.txt; provide it as argument or set $GOROOT\n")
302 os.Exit(1)
303 }
304
305 f, err := os.Open(file)
306 if err != nil {
307 fmt.Fprintf(os.Stderr, "error opening %v: %v\n", file, err)
308 os.Exit(1)
309 }
310 fi = bufio.NewReader(f)
311
312 one.vval = 1
313
314 /*
315 * read the 'units' file to
316 * develop a database
317 */
318 lineno = 0
319 for {
320 lineno++
321 if readline() {
322 break
323 }
324 if len(line) == 0 || line[0] == '/' {
325 continue
326 }
327 peekrune = ':'
328 units_Parse(UnitsLex(0))
329 }
330
331 /*
332 * read the console to
333 * print ratio of pairs
334 */
335 fi = bufio.NewReader(os.NewFile(0, "stdin"))
336
337 lineno = 0
338 for {
339 if (lineno & 1) != 0 {
340 fmt.Printf("you want: ")
341 } else {
342 fmt.Printf("you have: ")
343 }
344 if readline() {
345 break
346 }
347 peekrune = '?'
348 nerrors = 0
349 units_Parse(UnitsLex(0))
350 if nerrors != 0 {
351 continue
352 }
353 if (lineno & 1) != 0 {
354 if specialcase(&retnode, &retnode2, &retnode1) {
355 fmt.Printf("\tis %v\n", &retnode)
356 } else {
357 div(&retnode, &retnode2, &retnode1)
358 fmt.Printf("\t* %v\n", &retnode)
359 div(&retnode, &retnode1, &retnode2)
360 fmt.Printf("\t/ %v\n", &retnode)
361 }
362 } else {
363 retnode2 = retnode1
364 }
365 lineno++
366 }
367 fmt.Printf("\n")
368 os.Exit(0)
369 }
370
371 /*
372 * all characters that have some
373 * meaning. rest are usable as names
374 */
375 func ralpha(c rune) bool {
376 switch c {
377 case 0, '+', '-', '*', '/', '[', ']', '(', ')',
378 '^', ':', '?', ' ', '\t', '.', '|', '#',
379 '×', '÷', '¹', 'ⁱ', '²', '⁲', '³', '⁳':
380 return false
381 }
382 return true
383 }
384
385 /*
386 * number forming character
387 */
388 func rdigit(c rune) bool {
389 switch c {
390 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
391 '.', 'e', '+', '-':
392 return true
393 }
394 return false
395 }
396
397 func Errorf(s string, v ...interface{}) {
398 fmt.Printf("%v: %v\n\t", lineno, line)
399 fmt.Printf(s, v...)
400 fmt.Printf("\n")
401
402 nerrors++
403 if nerrors > 5 {
404 fmt.Printf("too many errors\n")
405 os.Exit(1)
406 }
407 }
408
409 func Error(s string) {
410 Errorf("%s", s)
411 }
412
413 func add(c, a, b *Node) {
414 var i int
415 var d int8
416
417 for i = 0; i < Ndim; i++ {
418 d = a.dim[i]
419 c.dim[i] = d
420 if d != b.dim[i] {
421 Error("add must be like units")
422 }
423 }
424 c.vval = fadd(a.vval, b.vval)
425 }
426
427 func sub(c, a, b *Node) {
428 var i int
429 var d int8
430
431 for i = 0; i < Ndim; i++ {
432 d = a.dim[i]
433 c.dim[i] = d
434 if d != b.dim[i] {
435 Error("sub must be like units")
436 }
437 }
438 c.vval = fadd(a.vval, -b.vval)
439 }
440
441 func mul(c, a, b *Node) {
442 var i int
443
444 for i = 0; i < Ndim; i++ {
445 c.dim[i] = a.dim[i] + b.dim[i]
446 }
447 c.vval = fmul(a.vval, b.vval)
448 }
449
450 func div(c, a, b *Node) {
451 var i int
452
453 for i = 0; i < Ndim; i++ {
454 c.dim[i] = a.dim[i] - b.dim[i]
455 }
456 c.vval = fdiv(a.vval, b.vval)
457 }
458
459 func xpn(c, a *Node, b int) {
460 var i int
461
462 *c = one
463 if b < 0 {
464 b = -b
465 for i = 0; i < b; i++ {
466 div(c, c, a)
467 }
468 } else {
469 for i = 0; i < b; i++ {
470 mul(c, c, a)
471 }
472 }
473 }
474
475 func specialcase(c, a, b *Node) bool {
476 var i int
477 var d, d1, d2 int8
478
479 d1 = 0
480 d2 = 0
481 for i = 1; i < Ndim; i++ {
482 d = a.dim[i]
483 if d != 0 {
484 if d != 1 || d1 != 0 {
485 return false
486 }
487 d1 = int8(i)
488 }
489 d = b.dim[i]
490 if d != 0 {
491 if d != 1 || d2 != 0 {
492 return false
493 }
494 d2 = int8(i)
495 }
496 }
497 if d1 == 0 || d2 == 0 {
498 return false
499 }
500
501 if fund[d1].name == "°C" && fund[d2].name == "°F" &&
502 b.vval == 1 {
503 for ll := 0; ll < len(c.dim); ll++ {
504 c.dim[ll] = b.dim[ll]
505 }
506 c.vval = a.vval*9./5. + 32.
507 return true
508 }
509
510 if fund[d1].name == "°F" && fund[d2].name == "°C" &&
511 b.vval == 1 {
512 for ll := 0; ll < len(c.dim); ll++ {
513 c.dim[ll] = b.dim[ll]
514 }
515 c.vval = (a.vval - 32.) * 5. / 9.
516 return true
517 }
518 return false
519 }
520
521 func printdim(str string, d, n int) string {
522 var v *Var
523
524 if n != 0 {
525 v = fund[d]
526 if v != nil {
527 str += fmt.Sprintf("%v", v.name)
528 } else {
529 str += fmt.Sprintf("[%d]", d)
530 }
531 switch n {
532 case 1:
533 break
534 case 2:
535 str += "²"
536 case 3:
537 str += "³"
538 default:
539 str += fmt.Sprintf("^%d", n)
540 }
541 }
542 return str
543 }
544
545 func (n Node) String() string {
546 var str string
547 var f, i, d int
548
549 str = fmt.Sprintf("%.7e ", n.vval)
550
551 f = 0
552 for i = 1; i < Ndim; i++ {
553 d = int(n.dim[i])
554 if d > 0 {
555 str = printdim(str, i, d)
556 } else if d < 0 {
557 f = 1
558 }
559 }
560
561 if f != 0 {
562 str += " /"
563 for i = 1; i < Ndim; i++ {
564 d = int(n.dim[i])
565 if d < 0 {
566 str = printdim(str, i, -d)
567 }
568 }
569 }
570
571 return str
572 }
573
574 func (v *Var) String() string {
575 var str string
576 str = fmt.Sprintf("%v %v", v.name, v.node)
577 return str
578 }
579
580 func readline() bool {
581 s, err := fi.ReadString('\n')
582 if err != nil {
583 return true
584 }
585 line = s
586 linep = 0
587 return false
588 }
589
590 func getrune() rune {
591 var c rune
592 var n int
593
594 if linep >= len(line) {
595 return 0
596 }
597 c, n = utf8.DecodeRuneInString(line[linep:len(line)])
598 linep += n
599 if c == '\n' {
600 c = 0
601 }
602 return c
603 }
604
605 var symmap = make(map[string]*Var) // symbol table
606
607 func lookup(f int) *Var {
608 var p float64
609 var w *Var
610
611 v, ok := symmap[sym]
612 if ok {
613 return v
614 }
615 if f != 0 {
616 return nil
617 }
618 v = new(Var)
619 v.name = sym
620 symmap[sym] = v
621
622 p = 1
623 for {
624 p = fmul(p, pname())
625 if p == 0 {
626 break
627 }
628 w = lookup(1)
629 if w != nil {
630 v.node = w.node
631 v.node.vval = fmul(v.node.vval, p)
632 break
633 }
634 }
635 return v
636 }
637
638 type Prefix struct {
639 vval float64
640 name string
641 }
642
643 var prefix = []Prefix{ // prefix table
644 {1e-24, "yocto"},
645 {1e-21, "zepto"},
646 {1e-18, "atto"},
647 {1e-15, "femto"},
648 {1e-12, "pico"},
649 {1e-9, "nano"},
650 {1e-6, "micro"},
651 {1e-6, "μ"},
652 {1e-3, "milli"},
653 {1e-2, "centi"},
654 {1e-1, "deci"},
655 {1e1, "deka"},
656 {1e2, "hecta"},
657 {1e2, "hecto"},
658 {1e3, "kilo"},
659 {1e6, "mega"},
660 {1e6, "meg"},
661 {1e9, "giga"},
662 {1e12, "tera"},
663 {1e15, "peta"},
664 {1e18, "exa"},
665 {1e21, "zetta"},
666 {1e24, "yotta"},
667 }
668
669 func pname() float64 {
670 var i, j, n int
671 var s string
672
673 /*
674 * rip off normal prefixs
675 */
676 n = len(sym)
677 for i = 0; i < len(prefix); i++ {
678 s = prefix[i].name
679 j = len(s)
680 if j < n && sym[0:j] == s {
681 sym = sym[j:n]
682 return prefix[i].vval
683 }
684 }
685
686 /*
687 * rip off 's' suffixes
688 */
689 if n > 2 && sym[n-1] == 's' {
690 sym = sym[0 : n-1]
691 return 1
692 }
693
694 return 0
695 }
696
697 // careful multiplication
698 // exponents (log) are checked before multiply
699 func fmul(a, b float64) float64 {
700 var l float64
701
702 if b <= 0 {
703 if b == 0 {
704 return 0
705 }
706 l = math.Log(-b)
707 } else {
708 l = math.Log(b)
709 }
710
711 if a <= 0 {
712 if a == 0 {
713 return 0
714 }
715 l += math.Log(-a)
716 } else {
717 l += math.Log(a)
718 }
719
720 if l > Maxe {
721 Error("overflow in multiply")
722 return 1
723 }
724 if l < -Maxe {
725 Error("underflow in multiply")
726 return 0
727 }
728 return a * b
729 }
730
731 // careful division
732 // exponents (log) are checked before divide
733 func fdiv(a, b float64) float64 {
734 var l float64
735
736 if b <= 0 {
737 if b == 0 {
738 Errorf("division by zero: %v %v", a, b)
739 return 1
740 }
741 l = math.Log(-b)
742 } else {
743 l = math.Log(b)
744 }
745
746 if a <= 0 {
747 if a == 0 {
748 return 0
749 }
750 l -= math.Log(-a)
751 } else {
752 l -= math.Log(a)
753 }
754
755 if l < -Maxe {
756 Error("overflow in divide")
757 return 1
758 }
759 if l > Maxe {
760 Error("underflow in divide")
761 return 0
762 }
763 return a / b
764 }
765
766 func fadd(a, b float64) float64 {
767 return a + b
768 }
OLDNEW
« src/cmd/yacc/expr.y ('K') | « src/cmd/yacc/units.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b