rendered paste body%{
// calc is an yacc based toy calculator written in Go.
package main
import (
"bufio"
"fmt"
"os"
"unicode"
)
%}
%union{
val float64
}
%type <val> expr
%token <val> NUMBER
%left '+' '-'
%left '*' '/' '%'
%left UMINUS
%%
list
: // nothing.
| list '\n'
| list expr '\n' { fmt.Println($2) }
;
expr
: '(' expr ')' { $$ = $2 }
| expr '+' expr { $$ = $1 + $3 }
| expr '-' expr { $$ = $1 - $3 }
| expr '*' expr { $$ = $1 * $3 }
| expr '/' expr { $$ = $1 / $3 }
| '-' expr %prec UMINUS { $$ = -$2 }
| NUMBER
;
%%
type calcLex struct {
br *bufio.Reader
}
func (l *calcLex) Lex(lval *yySymType) int {
for {
r, _, err := l.br.ReadRune()
if err != nil {
break;
}
switch {
// explicit, so the case below doesn't eat it.
case r == '\n':
return int(r)
case unicode.IsSpace(r):
continue
case r == '.':
fallthrough
case unicode.IsDigit(r):
l.br.UnreadRune()
fmt.Fscanf(l.br, "%f", &lval.val)
return NUMBER
default:
return int(r)
}
}
return 0
}
func (l *calcLex) Error(s string) {
fmt.Println(s)
}
func main() {
yyParse(&calcLex{br: bufio.NewReader(os.Stdin)})
}