2007.05.26 maita & Nakai "Language" Lab.
$ sudo gem install depager
or
$ tar xvzf depager-0.1.9.tgz $ cd depager $ sudo ruby setup.rb
If you use emacs, depager-mode.el is available.
$ cd <depager-root> $ cp data/depager/misc/depager-mode.el <your site-lisp>
Then modify your .emacs as following.
(autoload 'depager-mode "depager-mode" "alternate mode for editing depager files" t)
(setq auto-mode-alist (append '(("\\.dr$" . depager-mode)) auto-mode-alist))
$ depager -o outputfine inputfile
Note: val[x] is the value of the x-th symbol in right hand side.
%class TinyCalc
%extend Lexer ('depager/lex.rb')
%extend Action ('depager/action.rb')
%decorate @Action
%%
%LEX{
/\s+/, /\#.*/ { }
/[1-9][0-9]*/ { yield _Token(:NUM, $&.to_i) }
/./ { yield _Token($&, $&) }
%}
#begin-rule
expr :
expr '+' term { val[0] + val[2] }
| expr '-' term { val[0] - val[2] }
| term { val[0] }
;
term :
term '*' fact { val[0] * val[2] }
| term '/' fact { val[0] / val[2] }
| fact { val[0] }
;
fact :
NUM { val[0].value }
| '(' expr ')' { val[1] }
;
#end-rule
%%
parser = TinyCalc::createDecoratedParser
r, = parser.yyparse(STDIN)
puts r
Note: ~node is the child node of the AST node.
%class TinyCalc
%extend Lexer ('depager/lex.rb')
%extend ASTBuilderDepthFirst ('depager/astdf.rb')
%decorate @ASTBuilderDepthFirst
%%
%LEX{
/\s+/, /\#.*/ { }
/[1-9][0-9]*/ { yield _Token(:NUM, $&.to_i) }
/./ { yield _Token($&, $&) }
%}
%AST{
Node [value] { @value = nil }
Visitor { }
add(left, right) { ~value = ~left.value + ~right.value }
sub(left, right) { ~value = ~left.value - ~right.value }
mul(left, right) { ~value = ~left.value * ~right.value }
div(left, right) { ~value = ~left.value / ~right.value }
literal(-n) { ~value = ~n.value }
%}
#begin-rule
expr :
expr '+' term
=> add(expr, term)
| expr '-' term
=> sub(expr, term)
| term
=> term
;
term :
term '*' fact
=> mul(term, fact)
| term '/' fact
=> div(term, fact)
| fact
=> fact
;
fact :
NUM
=> literal(NUM)
| '(' expr ')'
=> expr
;
#end-rule
%%
require 'pp'
parser = TinyCalc::createDecoratedParser
t, = parser.yyparse(STDIN)
v = Visitor.new
pp t.accept(v).value
pp t
GPL.