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
This commit is contained in:
Ian Lance Taylor 2013-09-11 09:01:47 -07:00
parent ab38e2a498
commit fdaf88ea5b
5 changed files with 211 additions and 1352 deletions

View File

@ -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

View File

@ -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:

205
src/cmd/yacc/expr.y Normal file
View File

@ -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
// > <type an expression>
%{
// 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 <num> expr expr1 expr2 expr3
%token <num> 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 <prefix>Lex as a lexer. It must provide
// the methods Lex(*<prefix>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})
}
}

View File

@ -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

View File

@ -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 <node> prog expr expr0 expr1 expr2 expr3 expr4
%token <vval> VÄL // dieresis to test UTF-8
%token <vvar> VAR
%token <numb> _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
}