bison マニュアルの多機能電卓 練習問題2

JFlex を使って

%%

%class Scanner
%implements Test.yyInput

%type int

%eofval{
    return YYEOF;
%eofval}

%{
    private int token;
    protected Object value;

    public boolean advance() throws java.io.IOException {
        token = yylex();
        return token != YYEOF;
    }

    public int token() {
        return token;
    }

    public Object value() {
        return value;
    }
%}

space   = [\ \t\b\015]+
digit   = [0-9]
integer = {digit}+
real    = ({digit}+"."{digit}*|{digit}*"."{digit}+)
id      = [a-zA-Z][a-zA-Z0-9]*

%%

{space}              { }
{integer}|{real}     { value = new Double(yytext()); return Test.NUM; }
{id}                 {
                       Obj s = Test.getsym(yytext());
                       if (s == null) {
                         s = Test.putsym(yytext(), Test.VAR);
                       }
                       value = s;
                       return s.type;
                     }
.|\n                 { value = null; return yytext().charAt(0); }

と、

%{

import java.io.*;
import java.util.*;

class Obj {
  public String name;
  public int    type;
  public double val;

  Obj(String s, int t, double v) {
    name = s; type = t; val = v;
  }
}

public class Test {

%}

%token NUM
%type <Double> exp NUM
%token <Obj> VAR FNCT   /* 変数と関数 */

%right '='
%left '-' '+'
%left '*' '/'
%left NEG     /* negation--単項マイナス */
%right '^'    /* べき乗関数        */

%%

input:    /* 空 */
        | input line
;

line:     '\n'
        | exp   '\n' { System.out.println("\t" + $1); }
        | error '\n' { yyErrorFlag = 0; }
;

exp:      NUM                { $$ = new Double($1.doubleValue());  }
        | VAR                { $$ = new Double($1.val);            }
        | VAR '=' exp        { $$ = new Double($3.doubleValue()); $1.val = $3.doubleValue(); }
        | FNCT '(' exp ')'   { $$ = new Double(func($1.name, $3.doubleValue()));        }
        | exp '+' exp        { $$ = new Double($1.doubleValue() + $3.doubleValue());    }
        | exp '-' exp        { $$ = new Double($1.doubleValue() - $3.doubleValue());    }
        | exp '*' exp        { $$ = new Double($1.doubleValue() * $3.doubleValue());    }
        | exp '/' exp        { $$ = new Double($1.doubleValue() / $3.doubleValue());    }
        | '-' exp  %prec NEG { $$ = new Double(-$2.doubleValue());        }
        | exp '^' exp        { $$ = new Double(Math.pow($1.doubleValue(), $3.doubleValue())); }
        | '(' exp ')'        { $$ = new Double($2.doubleValue());         }
;

%%

  private static Map sym = new HashMap();

  private static void init_table() {
    putsym("sin",  FNCT);
    putsym("cos",  FNCT);
    putsym("atan", FNCT);
    putsym("ln",   FNCT);
    putsym("exp",  FNCT);
    putsym("sqrt", FNCT);

    Obj x;
    x = new Obj("PI", VAR, 3.14159265358979); sym.put("PI", x);
    x = new Obj("E",  VAR, 2.71828182845905); sym.put("E",  x);
  }

  public static Obj putsym(String sym_name, int sym_type) {
    Obj x = new Obj(sym_name, sym_type, 0);
    sym.put(sym_name, x);

    return x;
  }

  public static Obj getsym(String sym_name) {
    if (sym.containsKey(sym_name)) {
      return (Obj)sym.get(sym_name);
    } else {
      return null;
    }
  }

  private double func(String sym_name, double v) {
    if (sym_name == "sin") {
      return Math.sin(v);
    } else if (sym_name == "cos") {
      return Math.cos(v);
    } else if (sym_name == "atan") {
      return Math.atan(v);
    } else if (sym_name == "ln") {
      return Math.log(v);
    } else if (sym_name == "exp") {
      return Math.exp(v);
    } else if (sym_name == "sqrt") {
      return Math.sqrt(v);
    } else {
      return 0;
    }
  }

  public static void main (String args []) {
    init_table();

    Scanner scanner = new Scanner(new InputStreamReader(System.in));
    try {
      new Test().yyparse(scanner);
    } catch (IOException ie) { ie.printStackTrace(); }
      catch (yyException ye) { System.err.println(ye); }
  }

}

で、

PI
	3.14159265358979
PI * 2
	6.28318530717958
E
	2.71828182845905
ln(E)
	1.0000000000000018