From fdaf88ea5b7a3bc937e68875d55b5741ecb2f092 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 11 Sep 2013 09:01:47 -0700 Subject: [PATCH] cmd/yacc: replace units example with simpler expr example The units example is nice but is covered by the Lucent license, which may be a concern for some people making a commercial source code distribution of Go. R=golang-dev, r CC=golang-dev https://golang.org/cl/13283045 --- src/cmd/yacc/Makefile | 8 +- src/cmd/yacc/doc.go | 6 +- src/cmd/yacc/expr.y | 205 +++++++++++ src/cmd/yacc/units.txt | 576 ------------------------------- src/cmd/yacc/units.y | 768 ----------------------------------------- 5 files changed, 211 insertions(+), 1352 deletions(-) create mode 100644 src/cmd/yacc/expr.y delete mode 100644 src/cmd/yacc/units.txt delete mode 100644 src/cmd/yacc/units.y diff --git a/src/cmd/yacc/Makefile b/src/cmd/yacc/Makefile index 56e954289a..480844805f 100644 --- a/src/cmd/yacc/Makefile +++ b/src/cmd/yacc/Makefile @@ -2,9 +2,9 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -units: yacc.go units.y - go run yacc.go -p units_ units.y - go build -o units y.go +expr: yacc.go expr.y + go run yacc.go -p expr expr.y + go build -o expr y.go clean: - rm -f y.go y.output units + rm -f y.go y.output expr diff --git a/src/cmd/yacc/doc.go b/src/cmd/yacc/doc.go index 792c104e3d..ceaaf2448d 100644 --- a/src/cmd/yacc/doc.go +++ b/src/cmd/yacc/doc.go @@ -20,10 +20,8 @@ written in C and documented at Adepts of the original yacc will have no trouble adapting to this form of the tool. -The file units.y in this directory is a yacc grammar for a version of -the Unix tool units, also written in Go and largely transliterated -from the Plan 9 C version. It needs the flag "-p units_" (see -below). +The file expr.y in this directory is a yacc grammar for a very simple +expression parser. It needs the flag "-p expr" (see below). The generated parser is reentrant. Parse expects to be given an argument that conforms to the following interface: diff --git a/src/cmd/yacc/expr.y b/src/cmd/yacc/expr.y new file mode 100644 index 0000000000..3afffe7ee8 --- /dev/null +++ b/src/cmd/yacc/expr.y @@ -0,0 +1,205 @@ +// Copyright 2013 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. + +// This is an example of a goyacc program. +// To build it: +// go tool yacc -p "expr" expr.y (produces y.go) +// go build -o expr y.go +// expr +// > + +%{ + +// This tag will be copied to the generated file to prevent that file +// confusing a future build. + +// +build ignore + +package main + +import ( + "bufio" + "bytes" + "fmt" + "io" + "log" + "math/big" + "os" + "unicode/utf8" +) + +%} + +%union { + num *big.Rat +} + +%type expr expr1 expr2 expr3 + +%token NUM + +%% + +top: + expr + { + if $1.IsInt() { + fmt.Println($1.Num().String()) + } else { + fmt.Println($1.String()) + } + } + +expr: + expr1 +| '+' expr + { + $$ = $2 + } +| '-' expr + { + $$.Neg($2) + } + +expr1: + expr2 +| expr1 '+' expr2 + { + $$.Add($1, $3) + } +| expr1 '-' expr2 + { + $$.Sub($1, $3) + } + +expr2: + expr3 +| expr2 '*' expr3 + { + $$.Mul($1, $3) + } +| expr2 '/' expr3 + { + $$.Quo($1, $3) + } + +expr3: + NUM +| '(' expr ')' + { + $$ = $2 + } + + +%% + +// The parser expects the lexer to return 0 on EOF. Give it a name +// for clarity. +const eof = 0 + +// The parser uses the type Lex as a lexer. It must provide +// the methods Lex(*SymType) int and Error(string). +type exprLex struct { + line []byte + peek rune +} + +// The parser calls this method to get each new token. This +// implementation returns operators and NUM. +func (x *exprLex) Lex(yylval *exprSymType) int { + for { + c := x.next() + switch c { + case eof: + return eof + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return x.num(c, yylval) + case '+', '-', '*', '/', '(', ')': + return int(c) + + // Recognize Unicode multiplication and division + // symbols, returning what the parser expects. + case '×': + return '*' + case '÷': + return '/' + + case ' ', '\t', '\n': + default: + log.Printf("unrecognized character %q", c) + } + } +} + +// Lex a number. +func (x *exprLex) num(c rune, yylval *exprSymType) int { + add := func(b *bytes.Buffer, c rune) { + if _, err := b.WriteRune(c); err != nil { + log.Fatalf("WriteRune: %s", err) + } + } + var b bytes.Buffer + add(&b, c) + L: for { + c = x.next() + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E': + add(&b, c) + default: + break L + } + } + if c != eof { + x.peek = c + } + yylval.num = &big.Rat{} + _, ok := yylval.num.SetString(b.String()) + if !ok { + log.Printf("bad number %q", b.String()) + return eof + } + return NUM +} + +// Return the next rune for the lexer. +func (x *exprLex) next() rune { + if x.peek != eof { + r := x.peek + x.peek = eof + return r + } + if len(x.line) == 0 { + return eof + } + c, size := utf8.DecodeRune(x.line) + x.line = x.line[size:] + if c == utf8.RuneError && size == 1 { + log.Print("invalid utf8") + return x.next() + } + return c +} + +// The parser calls this method on a parse error. +func (x *exprLex) Error(s string) { + log.Printf("parse error: %s", s) +} + +func main() { + in := bufio.NewReader(os.Stdin) + for { + if _, err := os.Stdout.WriteString("> "); err != nil { + log.Fatalf("WriteString: %s", err) + } + line, err := in.ReadBytes('\n') + if err == io.EOF { + return + } + if err != nil { + log.Fatalf("ReadBytes: %s", err) + } + + exprParse(&exprLex{line: line}) + } +} diff --git a/src/cmd/yacc/units.txt b/src/cmd/yacc/units.txt deleted file mode 100644 index 7df23717ef..0000000000 --- a/src/cmd/yacc/units.txt +++ /dev/null @@ -1,576 +0,0 @@ -/ Plan 9's /lib/units -/ http://plan9.bell-labs.com/sources/plan9/lib/units -/ -/ Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved. -/ Distributed under the terms of the Lucent Public License Version 1.02 -/ See http://plan9.bell-labs.com/plan9/license.html -/ -/order of evaluation -/ + - -/ * / -/ juxtaposition (meaning *) -/ ¹ ² ³ ^ -/ | (meaning /) -/ name number () - -/dimensions -m # -kg # -sec # -coul # -candela # -$ # -radian # -bit # -erlang # -°K # -°C # -°F # - -/constants - -π 3.14159265358979323846 -pi π -c 2.997925e+8 m/sec -g 9.80665 m/sec² -au 1.49597871e+11 m -mole 6.022169e+23 -e 1.6021917e-19 coul -energy c² -force g -mercury 1.33322e+5 kg/m²sec² -hg mercury -h 6.62620e-34 m²kg/sec -ℏ h/2 π -hbar ℏ -nonillion 1e30 -octillion 1e27 -septillion 1e24 -sextillion 1e21 -pentillion 1e18 -quadrillion 1e15 -trillion 1e12 -billion 1e9 -million 1e6 -thousand 1e3 -hundred 1e2 - -/dimensionless - -° 1|180 π radian -degree ° -circle 2 π radian -turn 2 π radian -grad .9 ° -arcdeg 1 ° -arcmin 1|60 ° -arcsec 1|3600 ° -ccs 1|36 erlang - -steradian radian² -sphere 4 π steradian -sr steradian -giga 1024 1024 1024 - -/Time - -second sec -s sec -minute 60 sec -min minute -hour 60 min -hr hour -day 24 hr -da day -week 7 day -year 365.24219879 day -yr year -month 1|12 year -ms millisec -us microsec - -/Mass - -gram millikg -gm gram -mg milligram -metricton kilokg - -/Avoirdupois - -lb .45359237 kg -lbf lb g -pound lb -ounce 1|16 lb -oz ounce -dram 1|16 oz -dr dram -grain 1|7000 lb -gr grain -shortton 2000 lb -ton shortton -longton 2240 lb - -/Apothecary - -scruple 20 grain -apdram 60 grain -apounce 480 grain -troyounce apounce -appound 5760 grain -troypound appound - -/Length - -meter m -cm centimeter -mm millimeter -km kilometer -nm nanometer -micron micrometer -µ micrometer -Å decinanometer -angstrom Å - -inch 2.54 cm -" inch -in inch -inches inch -' 12" -foot 12 in -feet foot -ft foot -yard 3 ft -yd yard -rod 5.5 yd -rd rod -mile 5280 ft -mi mile - -british 1200|3937 m/ft -nmile 1852 m - -acre 4840 yd² - -cc cm³ -liter kilocc -ml milliliter - -/US Liquid - -gallon 231 in³ -imperial 1.20095 -epa 0.8 -gal gallon -quart 1|4 gal -qt quart -pint 1|2 qt -pt pint - -floz 1|16 pt -fldr 1|8 floz - -/US Dry - -dry 268.8025 in³/gallon -peck 8 dry quart -pk peck -bushel 4 peck -bu bushel - -/British - -brgallon 277.420 in³ -brquart 1|4 brgallon -brpint 1|2 brquart -brfloz 1|20 brpint -brpeck 554.84 in³ -brbushel 4 brpeck - -/Energy Work - -newton kg m/sec² -nt newton -joule nt m -cal 4.1868 joule - -/Electrical - -coulomb coul -ampere coul/sec -amp ampere -watt joule/sec -volt watt/amp -Ω volt/amp -ohm Ω -mho 1/Ω -farad coul/volt -henry sec²/farad -weber volt sec - -/Light - -cd candela -lumen cd sr -lux cd sr/m² - -/ MONEY DATE -/ Wed Aug 29, 2012 - -argentinapeso $ 0.2160 -australiadollar $ 1.0372 -boliviaboliviano $ 0.1427 -brazilreal $ 0.4872 -britainpound $ 1.5843 -canadadollar $ 1.0117 -chilepeso $ 1 | 480.6 -chinayuan $ 0.1574 -colombiapeso $ 1 | 1834 -czechkoruna $ 0.0506 -denmarkkrone $ 0.1681 -dominicanpeso $ 0.0256 -egyptpound $ 0.1640 -elsalvadorcolon $ 1 | 8.75 -europeuro $ 1.2528 -guatemalaquetzal $ 0.1290 -honduraslempira $ 0.0511 -hongkongdollar $ 0.1289 -hungaryforint $ 1 | 226.5 -indiarupee $ 0.0180 -indonesiarupiah $ 1 | 9540 -israelshekel $ 0.2479 -japanyen $ 0.0127 -kenyashilling $ 0.0119 -kuwaitdinar $ 3.5456 -lebanonpound $ 1 | 1505.5 -malaysiaringgit $ 0.3204 -mexicopeso $ 0.0754 -newzealanddollar $ 0.8035 -nicaraguacordoba $ 0.0421 -norwaykrone $ 0.1717 -pakistanrupee $ 0.0106 -paraguayguarani $ 1 | 4415 -perunewsol $ 0.3832 -philippinespeso $ 0.0236 -polandzloty $ 0.3001 -russiaruble $ 0.0311 -saudiarabiariyal $ 1 | 3.75 -singaporedollar $ 0.7976 -slovakkoruna 1 | 30.126 europeuro -southafricarand $ 0.1188 -southkoreawon $ 1 | 1135 -swedenkrona $ 0.1502 -switzerlandfranc $ 1.0431 -taiwandollar $ 0.0334 -thailandbaht $ 0.0319 -turkeynewlira $ 0.5504 -uaedirham $ 0.2723 -uruguaynewpeso $ 0.0465 -vietnamdong $ 1 | 20865 - -/ END MONEY - -€ europeuro -£ britainpound -¥ japanyen -dollar $ - -baht thailandbaht -brpound britainpound -dirham uaedirham -euro europeuro -forint hungaryforint -krona swedenkrona -peso mexicopeso -rand southafricarand -real brazilreal -yuan chinayuan -ringgit malaysiaringgit -riyal saudiarabiariyal -ruble russiaruble -rupee indiarupee -rupiah indonesiarupiah -shekel israelshekel -sol perunewsol -won southkoreawon -yen japanyen -zloty polandzloty - -usdollar dollar -sterling britainpound | pound -poundsterling britainpound - -/bits - -baud bit/sec -byte 8 bit -short 2 byte -long 4 byte -vlong 8 bytes -frame 2352 byte - -/Australian liquid measure - -pony 7 brfloz -midie 10 brfloz -pot midie -handle midie -schooner 15 brfloz -jug 40 brfloz -resch midie -alf midie -tinny 13 brfloz -stubby tinny -twisty 250 ml -longneck 2 tinny -slab 24 tinny -sixpack 6 tinny -nip brfloz - -/wine -winebottle 750 ml -balthazar 16 winebottle -jeroboam 4 winebottle -magnum 2 winebottle -mathusalem 8 winebottle -methuselah 8 winebottle -nebuchadnezzar 20 winebottle -rehoboam 6 winebottle -salmanazar 12 winebottle -split 0.25 winebottle -jigger 1.5 floz - -/Trivia - -% 1|100 -admiraltyknot 6080 ft/hr -ε₀ (1e-9/36π) farad/m -α (1/4π ε₀) e²/ℏ c -alpha α -apostilb cd/π m² -are 1e+2 m² -arpentcan 27.52 mi -arpentlin 191.835 ft -astronomicalunit au -atmosphere 1.01325e+5 nt/m² -atm atmosphere -atomicmassunit 1.66044e-27 kg -amu atomicmassunit -bag 94 lb -bakersdozen 13 -bar 1e+5 nt/m² -barie 1e-1 nt/m² -barleycorn 1|3 in -barn 1e-28 m² -barrel 42 gal -barye 1e-1 nt/m² -bev 1e+9 e volt -biot 10 amp -blondel cd/π m² -boardfoot 144 in³ -bolt 40 yd -bottommeasure 1|40 in -britishthermalunit 1.05506e+3 joule -btu britishthermalunit -quad 1.0e+15 btu -refrigeration 12000 btu/ton hour -buck dollar -cable 720 ft -caliber 1e-2 in -calorie cal -carat 205 mg -cent centidollar -cental 100 lb -centesimalminute 1e-2 grad -centesimalsecond 1e-4 grad -century 100 year -cfs ft³/sec -chain 66 ft -circularinch 1|4 π in² -circularmil 1e-6|4 π in² -clusec 1e-8 mm hg m³/s -coomb 4 bu -cord 128 ft³ -cordfoot cord -crith 9.06e-2 gm -cubit 18 in -cup 1|2 pt -curie 3.7e+10/sec -cusec ft³/sec -dalton amu -decade 10 yr -degK °K -degC °C -degF °F -dipotre 1/m -displacementton 35 ft³ -doppelzentner 100 kg -dozen 12 -drop .03 cm³ -dyne cm gm/sec² -electronvolt e volt -ell 45 in -engineerschain 100 ft -engineerslink 100|100 ft -equivalentfootcandle lumen/π ft² -equivalentlux lumen/π m² -equivalentphot cd/π cm² -erg cm²gm/sec² -ev e volt -faraday 9.652e+4 coul -fathom 6 ft -fermi 1e-15 m -fifth 4|5 qt -fin 5 dollar -finger 7|8 in -firkin 9 gal -footcandle lumen/ft² -footlambert cd/π ft² -fortnight 14 da -franklin 3.33564e-10 coul -frigorie kilocal -furlong 220 yd -galileo 1e-2 m/sec² -gamma 1e-9 weber/m² -gauss 1e-4 weber/m² -geodeticfoot british ft -geographicalmile 1852 m -gilbert 7.95775e-1 amp -gill 1|4 pt -gross 144 -gunterschain 22 yd -hand 4 in -hectare 1e+4 m² -hefnercandle .92 cd -hertz 1/sec -hogshead 2 barrel -hd hogshead -homestead 1|4 mi² -horsepower 550 ft lb g/sec -hp horsepower -hyl gm force sec²/m -hz 1/sec -imaginarycubicfoot 1.4 ft³ -karat 1|24 -kcal kilocal -kcalorie kilocal -kev 1e+3 e volt -key kg -khz 1e+3/sec -kilderkin 18 gal -knot nmile/hr -kwh kilowatt hour -lambert cd/π cm² -langley cal/cm² -last 80 bu -league 3 mi -lightyear c yr -ly lightyear -lightsecond c sec -line 1|12 in -link 66|100 ft -longhundredweight 112 lb -longquarter 28 lb -lusec 1e-6 mm hg m³/s -mach 331.46 m/sec -marineleague 3 nmile -maxwell 1e-8 weber -metriccarat 200 mg -mev 1e+6 e volt -mgd megagal/day -mh millihenry -mhz 1e+6/sec -mil 1e-3 in -millennium 1000 year -minersinch 1.5 ft³/min -minim 1|60 fldr -mo month -mpg mile/gal -mph mile/hr -nail 1|16 yd -nauticalmile nmile -nit cd/m² -noggin 1|8 qt -nox 1e-3 lux -ns nanosec -oersted 2.5e+2 amp/m π -oe oersted -pace 36 in -palm 3 in -parasang 3.5 mi -parsec au radian/arcsec -pascal nt/m² -pc parsec -pennyweight 1|20 oz -percent % -perch rd -pf picofarad -phot lumen/cm² -pica 1|6 in -pieze 1e+3 nt/m² -pipe 4 barrel -point 1|72 in -poise gm/cm sec -pole rd -poundal ft lb/sec² -pdl poundal -proof 1/200 -psi lb g/in² -quarter 9 in -quartersection 1|4 mi² -quintal 100 kg -quire 25 -rad 100 erg/gm -ream 500 -registerton 100 ft³ -rhe 10 m²/nt sec -rontgen 2.58e-4 curie/kg -rood 1.21e+3 yd -rope 20 ft -rutherford 1e+6/sec -rydberg 1.36054e+1 ev -sabin 1 ft² -sack 3 bu -seam 8 bu -section mi² -shippington 40 ft³ -shorthundredweight 100 lb -shortquarter 25 lb -siemens 1/Ω -σ 5.66956e-5 erg/cm² °K^4 sec -sigma σ -skein 120 yd -skot 1e-3 apostilb -slug lb g sec²/ft -span 9 in -spat 4 π sr -spindle 14400 yd -square 100 ft² -squidge 1|972 inch -catsquidge 1|432 inch -stere m³ -sthene 1e+3 nt -stilb cd/cm² -stoke 1e-4 m²/sec -stone 14 lb -strike 2 bu -surveyfoot british ft -surveyorschain 66 ft -surveyorslink 66|100 ft -tablespoon 4 fldr -teaspoon 4|3 fldr -tesla weber/m² -therm 1e+5 btu -thermie 1e+6 cal -timberfoot ft³ -tnt 4.6e+6 m²/sec² -tonne 1e+6 gm -torr mm hg -township 36 mi² -tun 8 barrel -water .22491|2.54 kg/m²sec² -wey 40 bu -weymass 252 lb -Xunit 1.00202e-13 m -k 1.38047e-16 erg/°K -foal 9223372036854775807 diff --git a/src/cmd/yacc/units.y b/src/cmd/yacc/units.y deleted file mode 100644 index 9c1b0b3364..0000000000 --- a/src/cmd/yacc/units.y +++ /dev/null @@ -1,768 +0,0 @@ -// Derived from Plan 9's /sys/src/cmd/units.y -// http://plan9.bell-labs.com/sources/plan9/sys/src/cmd/units.y -// -// Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved. -// Portions Copyright 2009 The Go Authors. All Rights Reserved. -// Distributed under the terms of the Lucent Public License Version 1.02 -// See http://plan9.bell-labs.com/plan9/license.html - -// Generate parser with prefix "units_": -// go tool yacc -p "units_" - -%{ - -// This tag will end up in the generated y.go, so that forgetting -// 'make clean' does not fail the next build. - -// +build ignore - -// units.y -// example of a Go yacc program -// usage is -// go tool yacc -p "units_" units.y (produces y.go) -// go build -o units y.go -// ./units $GOROOT/src/cmd/yacc/units.txt -// you have: c -// you want: furlongs/fortnight -// * 1.8026178e+12 -// / 5.5474878e-13 -// you have: - -package main - -import ( - "bufio" - "flag" - "fmt" - "math" - "runtime" - "os" - "path/filepath" - "strconv" - "unicode/utf8" -) - -const ( - Ndim = 15 // number of dimensions - Maxe = 695 // log of largest number -) - -type Node struct { - vval float64 - dim [Ndim]int8 -} - -type Var struct { - name string - node Node -} - -var fi *bufio.Reader // input -var fund [Ndim]*Var // names of fundamental units -var line string // current input line -var lineno int // current input line number -var linep int // index to next rune in unput -var nerrors int // error count -var one Node // constant one -var peekrune rune // backup runt from input -var retnode1 Node -var retnode2 Node -var retnode Node -var sym string -var vflag bool -%} - -%union { - node Node - vvar *Var - numb int - vval float64 -} - -%type prog expr expr0 expr1 expr2 expr3 expr4 - -%token VÄL // dieresis to test UTF-8 -%token VAR -%token _SUP // tests leading underscore in token name -%% -prog: - ':' VAR expr - { - var f int - f = int($2.node.dim[0]) - $2.node = $3 - $2.node.dim[0] = 1 - if f != 0 { - Errorf("redefinition of %v", $2.name) - } else if vflag { - fmt.Printf("%v\t%v\n", $2.name, &$2.node) - } - } -| ':' VAR '#' - { - var f, i int - for i = 1; i < Ndim; i++ { - if fund[i] == nil { - break - } - } - if i >= Ndim { - Error("too many dimensions") - i = Ndim - 1 - } - fund[i] = $2 - f = int($2.node.dim[0]) - $2.node = one - $2.node.dim[0] = 1 - $2.node.dim[i] = 1 - if f != 0 { - Errorf("redefinition of %v", $2.name) - } else if vflag { - fmt.Printf("%v\t#\n", $2.name) - } - } -| ':' - { - } -| '?' expr - { - retnode1 = $2 - } -| '?' - { - retnode1 = one - } - -expr: - expr4 -| expr '+' expr4 - { - add(&$$, &$1, &$3) - } -| expr '-' expr4 - { - sub(&$$, &$1, &$3) - } - -expr4: - expr3 -| expr4 '*' expr3 - { - mul(&$$, &$1, &$3) - } -| expr4 '/' expr3 - { - div(&$$, &$1, &$3) - } - -expr3: - expr2 -| expr3 expr2 - { - mul(&$$, &$1, &$2) - } - -expr2: - expr1 -| expr2 _SUP - { - xpn(&$$, &$1, $2) - } -| expr2 '^' expr1 - { - var i int - for i = 1; i < Ndim; i++ { - if $3.dim[i] != 0 { - Error("exponent has units") - $$ = $1 - break - } - } - if i >= Ndim { - i = int($3.vval) - if float64(i) != $3.vval { - Error("exponent not integral") - } - xpn(&$$, &$1, i) - } - } - -expr1: - expr0 -| expr1 '|' expr0 - { - div(&$$, &$1, &$3) - } - -expr0: - VAR - { - if $1.node.dim[0] == 0 { - Errorf("undefined %v", $1.name) - $$ = one - } else { - $$ = $1.node - } - } -| VÄL - { - $$ = one - $$.vval = $1 - } -| '(' expr ')' - { - $$ = $2 - } -%% - -type UnitsLex int - -func (UnitsLex) Lex(yylval *units_SymType) int { - var c rune - var i int - - c = peekrune - peekrune = ' ' - -loop: - if (c >= '0' && c <= '9') || c == '.' { - goto numb - } - if ralpha(c) { - goto alpha - } - switch c { - case ' ', '\t': - c = getrune() - goto loop - case '×': - return '*' - case '÷': - return '/' - case '¹', 'ⁱ': - yylval.numb = 1 - return _SUP - case '²', '⁲': - yylval.numb = 2 - return _SUP - case '³', '⁳': - yylval.numb = 3 - return _SUP - } - return int(c) - -alpha: - sym = "" - for i = 0; ; i++ { - sym += string(c) - c = getrune() - if !ralpha(c) { - break - } - } - peekrune = c - yylval.vvar = lookup(0) - return VAR - -numb: - sym = "" - for i = 0; ; i++ { - sym += string(c) - c = getrune() - if !rdigit(c) { - break - } - } - peekrune = c - f, err := strconv.ParseFloat(sym, 64) - if err != nil { - fmt.Printf("error converting %v\n", sym) - f = 0 - } - yylval.vval = f - return VÄL -} - -func (UnitsLex) Error(s string) { - Errorf("syntax error, last name: %v", sym) -} - -func main() { - var file string - - flag.BoolVar(&vflag, "v", false, "verbose") - - flag.Parse() - - file = filepath.Join(runtime.GOROOT(), "src/cmd/yacc/units.txt") - if flag.NArg() > 0 { - file = flag.Arg(0) - } else if file == "" { - fmt.Fprintf(os.Stderr, "cannot find data file units.txt; provide it as argument or set $GOROOT\n") - os.Exit(1) - } - - f, err := os.Open(file) - if err != nil { - fmt.Fprintf(os.Stderr, "error opening %v: %v\n", file, err) - os.Exit(1) - } - fi = bufio.NewReader(f) - - one.vval = 1 - - /* - * read the 'units' file to - * develop a database - */ - lineno = 0 - for { - lineno++ - if readline() { - break - } - if len(line) == 0 || line[0] == '/' { - continue - } - peekrune = ':' - units_Parse(UnitsLex(0)) - } - - /* - * read the console to - * print ratio of pairs - */ - fi = bufio.NewReader(os.NewFile(0, "stdin")) - - lineno = 0 - for { - if (lineno & 1) != 0 { - fmt.Printf("you want: ") - } else { - fmt.Printf("you have: ") - } - if readline() { - break - } - peekrune = '?' - nerrors = 0 - units_Parse(UnitsLex(0)) - if nerrors != 0 { - continue - } - if (lineno & 1) != 0 { - if specialcase(&retnode, &retnode2, &retnode1) { - fmt.Printf("\tis %v\n", &retnode) - } else { - div(&retnode, &retnode2, &retnode1) - fmt.Printf("\t* %v\n", &retnode) - div(&retnode, &retnode1, &retnode2) - fmt.Printf("\t/ %v\n", &retnode) - } - } else { - retnode2 = retnode1 - } - lineno++ - } - fmt.Printf("\n") - os.Exit(0) -} - -/* - * all characters that have some - * meaning. rest are usable as names - */ -func ralpha(c rune) bool { - switch c { - case 0, '+', '-', '*', '/', '[', ']', '(', ')', - '^', ':', '?', ' ', '\t', '.', '|', '#', - '×', '÷', '¹', 'ⁱ', '²', '⁲', '³', '⁳': - return false - } - return true -} - -/* - * number forming character - */ -func rdigit(c rune) bool { - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '.', 'e', '+', '-': - return true - } - return false -} - -func Errorf(s string, v ...interface{}) { - fmt.Printf("%v: %v\n\t", lineno, line) - fmt.Printf(s, v...) - fmt.Printf("\n") - - nerrors++ - if nerrors > 5 { - fmt.Printf("too many errors\n") - os.Exit(1) - } -} - -func Error(s string) { - Errorf("%s", s) -} - -func add(c, a, b *Node) { - var i int - var d int8 - - for i = 0; i < Ndim; i++ { - d = a.dim[i] - c.dim[i] = d - if d != b.dim[i] { - Error("add must be like units") - } - } - c.vval = fadd(a.vval, b.vval) -} - -func sub(c, a, b *Node) { - var i int - var d int8 - - for i = 0; i < Ndim; i++ { - d = a.dim[i] - c.dim[i] = d - if d != b.dim[i] { - Error("sub must be like units") - } - } - c.vval = fadd(a.vval, -b.vval) -} - -func mul(c, a, b *Node) { - var i int - - for i = 0; i < Ndim; i++ { - c.dim[i] = a.dim[i] + b.dim[i] - } - c.vval = fmul(a.vval, b.vval) -} - -func div(c, a, b *Node) { - var i int - - for i = 0; i < Ndim; i++ { - c.dim[i] = a.dim[i] - b.dim[i] - } - c.vval = fdiv(a.vval, b.vval) -} - -func xpn(c, a *Node, b int) { - var i int - - *c = one - if b < 0 { - b = -b - for i = 0; i < b; i++ { - div(c, c, a) - } - } else { - for i = 0; i < b; i++ { - mul(c, c, a) - } - } -} - -func specialcase(c, a, b *Node) bool { - var i int - var d, d1, d2 int8 - - d1 = 0 - d2 = 0 - for i = 1; i < Ndim; i++ { - d = a.dim[i] - if d != 0 { - if d != 1 || d1 != 0 { - return false - } - d1 = int8(i) - } - d = b.dim[i] - if d != 0 { - if d != 1 || d2 != 0 { - return false - } - d2 = int8(i) - } - } - if d1 == 0 || d2 == 0 { - return false - } - - if fund[d1].name == "°C" && fund[d2].name == "°F" && - b.vval == 1 { - for ll := 0; ll < len(c.dim); ll++ { - c.dim[ll] = b.dim[ll] - } - c.vval = a.vval*9./5. + 32. - return true - } - - if fund[d1].name == "°F" && fund[d2].name == "°C" && - b.vval == 1 { - for ll := 0; ll < len(c.dim); ll++ { - c.dim[ll] = b.dim[ll] - } - c.vval = (a.vval - 32.) * 5. / 9. - return true - } - return false -} - -func printdim(str string, d, n int) string { - var v *Var - - if n != 0 { - v = fund[d] - if v != nil { - str += fmt.Sprintf("%v", v.name) - } else { - str += fmt.Sprintf("[%d]", d) - } - switch n { - case 1: - break - case 2: - str += "²" - case 3: - str += "³" - default: - str += fmt.Sprintf("^%d", n) - } - } - return str -} - -func (n Node) String() string { - var str string - var f, i, d int - - str = fmt.Sprintf("%.7e ", n.vval) - - f = 0 - for i = 1; i < Ndim; i++ { - d = int(n.dim[i]) - if d > 0 { - str = printdim(str, i, d) - } else if d < 0 { - f = 1 - } - } - - if f != 0 { - str += " /" - for i = 1; i < Ndim; i++ { - d = int(n.dim[i]) - if d < 0 { - str = printdim(str, i, -d) - } - } - } - - return str -} - -func (v *Var) String() string { - var str string - str = fmt.Sprintf("%v %v", v.name, v.node) - return str -} - -func readline() bool { - s, err := fi.ReadString('\n') - if err != nil { - return true - } - line = s - linep = 0 - return false -} - -func getrune() rune { - var c rune - var n int - - if linep >= len(line) { - return 0 - } - c, n = utf8.DecodeRuneInString(line[linep:len(line)]) - linep += n - if c == '\n' { - c = 0 - } - return c -} - -var symmap = make(map[string]*Var) // symbol table - -func lookup(f int) *Var { - var p float64 - var w *Var - - v, ok := symmap[sym] - if ok { - return v - } - if f != 0 { - return nil - } - v = new(Var) - v.name = sym - symmap[sym] = v - - p = 1 - for { - p = fmul(p, pname()) - if p == 0 { - break - } - w = lookup(1) - if w != nil { - v.node = w.node - v.node.vval = fmul(v.node.vval, p) - break - } - } - return v -} - -type Prefix struct { - vval float64 - name string -} - -var prefix = []Prefix{ // prefix table - {1e-24, "yocto"}, - {1e-21, "zepto"}, - {1e-18, "atto"}, - {1e-15, "femto"}, - {1e-12, "pico"}, - {1e-9, "nano"}, - {1e-6, "micro"}, - {1e-6, "μ"}, - {1e-3, "milli"}, - {1e-2, "centi"}, - {1e-1, "deci"}, - {1e1, "deka"}, - {1e2, "hecta"}, - {1e2, "hecto"}, - {1e3, "kilo"}, - {1e6, "mega"}, - {1e6, "meg"}, - {1e9, "giga"}, - {1e12, "tera"}, - {1e15, "peta"}, - {1e18, "exa"}, - {1e21, "zetta"}, - {1e24, "yotta"}, -} - -func pname() float64 { - var i, j, n int - var s string - - /* - * rip off normal prefixs - */ - n = len(sym) - for i = 0; i < len(prefix); i++ { - s = prefix[i].name - j = len(s) - if j < n && sym[0:j] == s { - sym = sym[j:n] - return prefix[i].vval - } - } - - /* - * rip off 's' suffixes - */ - if n > 2 && sym[n-1] == 's' { - sym = sym[0 : n-1] - return 1 - } - - return 0 -} - -// careful multiplication -// exponents (log) are checked before multiply -func fmul(a, b float64) float64 { - var l float64 - - if b <= 0 { - if b == 0 { - return 0 - } - l = math.Log(-b) - } else { - l = math.Log(b) - } - - if a <= 0 { - if a == 0 { - return 0 - } - l += math.Log(-a) - } else { - l += math.Log(a) - } - - if l > Maxe { - Error("overflow in multiply") - return 1 - } - if l < -Maxe { - Error("underflow in multiply") - return 0 - } - return a * b -} - -// careful division -// exponents (log) are checked before divide -func fdiv(a, b float64) float64 { - var l float64 - - if b <= 0 { - if b == 0 { - Errorf("division by zero: %v %v", a, b) - return 1 - } - l = math.Log(-b) - } else { - l = math.Log(b) - } - - if a <= 0 { - if a == 0 { - return 0 - } - l -= math.Log(-a) - } else { - l -= math.Log(a) - } - - if l < -Maxe { - Error("overflow in divide") - return 1 - } - if l > Maxe { - Error("underflow in divide") - return 0 - } - return a / b -} - -func fadd(a, b float64) float64 { - return a + b -} -- 2.50.0