継続は力にゃりん。毎日続けることができるのか?
候補
* tdp4r
* depager
* rex
* PEG
* jay
* SableCC
* JavaCC
* ANTLR
* Parse::RecDescent
* COINS
* Happy
* Parsec
* Camlp4
* notavacc
* Boost::spirit
とばし
* flex オプション
* flex %option
* flex C++ 継承してみるとか
* jflex flex examples を移植してみる(途中)
* bison YYBACKUP, YYEMPTY
* bison 先読み
* bison yyclearin
進捗
* 2008-02-24 PLY
* 2008-02-04 CUP
* 2008-01-01 Parse::Yapp
* 2007-11-28 racc
* 2007-10-30 kmyacc
* 2007-08-11 bison
* 2007-05-06 jflex
* 2007-01-01 flex
!2007-12-31 Mon
class Foo
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
a : 'a'
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
p [t, v, values]
p token_to_str(t)
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
b
を入力すると
syntax error
[1, "b", [nil]]
"error"
!2007-12-30 Sun
『コンパイラの基礎』の PL01 を受理する文法
class PL01
rule
prog : sub_progs MAIN main_prog
sub_progs :
| sub_progs sub_prog
sub_prog : FUNCTION ID '(' args ')' var_decl stat '.'
args :
| ids
main_prog : var_decl stat '.'
var_decl : VAR ids ';'
ids : ID
| ids ',' ID
stat : ID ':=' expr
| IF cond THEN stat
| WHILE cond DO stat
| BEGIN stats END
| WRITE expr
| RETURN expr
stats : stat
| stats ';' stat
cond : expr '=' expr
| expr '<>' expr
| expr '<' expr
| expr '>' expr
| expr '<=' expr
| expr '>=' expr
expr : term
| expr '+' term
| expr '-' term
term : fact
| term '*' fact
| term '/' fact
fact : ID
| NUM
| '(' expr ')' { result = val[1] }
| ID '(' func_arg ')'
func_arg :
| func_args
func_args : expr
| func_args ',' expr
end
---- inner
RESERVED = {
'main' => :MAIN,
'function' => :FUNCTION,
'var' => :VAR,
'if' => :IF,
'then' => :THEN,
'while' => :WHILE,
'do' => :DO,
'begin' => :BEGIN,
'end' => :END,
'write' => :WRITE,
'return' => :RETURN
}
def initialize
end
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A[a-zA-Z_]\w*/
word = $&
sym = $&.intern
if RESERVED[word]
@q.push [ RESERVED[word], sym ]
else
@q.push [ :ID, sym ]
end
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A(:=|<=|>=|<>)/
@q.push [ $&, $& ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
#@q.push [ :EOL, nil ]
#do_parse
end
#p @q
do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = PL01.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
function f(x)
var c,d;
begin
c := 1; d := x;
while d > 0 do begin c := c * d; d := d - 1 end;
return c
end.
main
var a,b;
begin
a := 3; b := f(a); write b
end.
を入力
!2007-12-29 Sat
『コンパイラの基礎』の PL00 を受理する文法
class PL00
rule
prog : main_prog
main_prog : var_decl stat '.'
var_decl : VAR ids ';'
ids : ID
| ids ',' ID
stat : ID ':=' expr
| IF cond THEN stat
| WHILE cond DO stat
| BEGIN stats END
| WRITE expr
stats : stat
| stats ';' stat
cond : expr '=' expr
| expr '<>' expr
| expr '<' expr
| expr '>' expr
| expr '<=' expr
| expr '>=' expr
expr : term
| expr '+' term
| expr '-' term
term : fact
| term '*' fact
| term '/' fact
fact : ID
| NUM
| '(' expr ')' { result = val[1] }
end
---- inner
RESERVED = {
'var' => :VAR,
'if' => :IF,
'then' => :THEN,
'while' => :WHILE,
'do' => :DO,
'begin' => :BEGIN,
'end' => :END,
'write' => :WRITE
}
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A[a-zA-Z_]\w*/
word = $&
sym = $&.intern
if RESERVED[word]
@q.push [ RESERVED[word], sym ]
else
@q.push [ :ID, sym ]
end
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A(:=|<=|>=|<>)/
@q.push [ $&, $& ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
#@q.push [ :EOL, nil ]
#do_parse
end
#p @q
do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = PL00.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
var a, b;
begin
a := 1; b := 3;
while b > 0 do begin a := a * b; b := b - 1 end;
write a
end.
を入力
!2007-12-28 Fri
引用符でかこまれているもの
は、HTML変換ミス(bug)?
これを変更する方法については、文法リファレンスを参照してください。
どこにそんな方法書いてあった?
!2007-12-27 Thu
class Foo
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
| error EOL
a : 'a' { puts "*a*" }
end
----inner
----footer
parser = Foo.new
(parser.methods - Object.new.methods).each { |x| p x }
で、
"_reduce_4"
"_reduce_6"
"_reduce_none"
!2007-12-26 Wed
class Foo
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
| error EOL
a : 'a' { puts "*a*" }
end
----inner
def initialize
Module.constants.grep(/racc/i).each { |x| p x }
end
----footer
parser = Foo.new
で、
"Racc_Runtime_Core_Version_R"
"Racc_Main_Parsing_Routine"
"Racc_Runtime_Version"
"Racc_Runtime_Core_Revision"
"Racc_debug_parser"
"Racc_Runtime_Core_Id_C"
"Racc_Runtime_Core_Version"
"Racc_arg"
"Racc_Runtime_Core_Revision_R"
"Racc_YY_Parse_Method"
"Racc"
"Racc_Runtime_Revision"
"Racc_Runtime_Type"
"Racc_Runtime_Core_Version_C"
"Racc_token_to_s_table"
"Racc_Runtime_Core_Revision_C"
!2007-12-25 Tue
class Foo
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
| error EOL
a : 'a' { puts "*a*" }
end
----header foo
#
# header
#
----innerFOO
#
# inner
#
----footerfoo
#
# footer
#
!2007-12-24 Mon
class Foo
start input
rule
line : EOL
| expr EOL { puts "\t#{val[0]}" }
| error EOL
expr : NUM
input :
| input line
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
1
1.0
2
2.0
!2007-12-23 Sun
class Foo
convert
NUM '"NUMBER"'
end
rule
input :
| input line
line : EOL
| expr EOL { puts "\t#{val[0]}" }
| error EOL
expr : NUM
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ "NUMBER", $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
1
1.0
ab
syntax error
!2007-12-22 Sat
class Foo
convert
NUM ':NUMBER'
end
rule
input :
| input line
line : EOL
| expr EOL { puts "\t#{val[0]}" }
| error EOL
expr : NUM
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUMBER, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
1
1.0
2
2.0
a
ab
syntax error
!2007-12-21 Fri
class Foo
expect 1
rule
input :
| input line
line : EOL
| stmt EOL { puts "\t#{val[0]}" }
| error EOL
stmt : expr
| if_stmt
if_stmt :
'I' expr 'T' stmt
| 'I' expr 'T' stmt 'E' stmt
expr : NUM
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、「expect 1」をつけないと、
1 shift/reduce conflicts
!2007-12-20 Thu
omit_action_call
何が変わるのか分からなかった…
1.4.5 で「--no-omit-actions が動作していなかったのを修正」、
おまけに 1.4.4 を使用のせい???
bug はオプションだけの話なのかも
!2007-12-19 Wed
2007-12-01 Sat で、
***************
*** 13,18 ****
--- 16,23 ----
class RPN
+ token EOL NUM
+
prechigh
right '^'
left UMINUS
で、コンパイル時
racc warning: terminal UMINUS used but not decleared
ルール内のトークンを間違えてみると、
racc warning: terminal UMINUS used but not decleared
racc warning: terminal EOL_ERROR used but not decleared
!2007-12-18 Tue
2007-12-01 Sat で、
***************
*** 13,24 ****
class RPN
- prechigh
- right '^'
- left UMINUS
- left '*' '/'
- left '+' '-'
preclow
rule
--- 15,26 ----
class RPN
preclow
+ left '+' '-'
+ left '*' '/'
+ left UMINUS
+ right '^'
+ prechigh
rule
「prechigh 〜 preclow」で書くと、どうも bison と逆になると思っていたら、
bisonマニュアルに
2個のトークンが別々の優先順位宣言で宣言されているならば、
文法ファイルの中で後で宣言されたほうの演算子が強い優先順位を持ちます。
という記述があった。
!2007-12-17 Mon
埋めこみアクション
class Foo
rule
input :
| input line
line : EOL
| ab EOL { puts "\t#{val[0]}" }
| error EOL
ab : 'a' { result = 1 }
'b' { p val }
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
ab
["a", 1, "b"]
a
!2007-12-16 Sun
class Foo
rule
input :
| input line
line : EOL
| ab EOL { puts "\t#{val[0]}" }
| error EOL
ab : 'a' { p _values }
'b' { p _values }
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
ab
[nil, "a"]
[nil]
a
絶対に
は、HTML変換ミス(bug)?
!2007-12-15 Sat
ルールの途中で改行
class Foo
rule
input :
| input line
line : EOL
| ab EOL { puts "\t#{val[0]}" }
| error EOL
ab : 'a'
'b'
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
ab
a
!2007-12-14 Fri
スペースで始まる正規表現
どんなのだ?
ごくまれに % の演算。普通に演算子のまわりにスペースを入れていれば問題なし
スペースを入れるのが「普通に」ということになっている…。
私も「普通に」スペースを入れるけど〜
class Foo
options no_result_var
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
| error EOL
a : 'a' { val[0][0] }
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
options no_result_var をつけないと、
a
a
options no_result_var をつけると、
a
97
!2007-12-13 Thu
class M::C
にすると、
module M
class C < Racc::Parser
に
!2007-12-12 Wed
class Foo < Bar
とすると、
class Foo < Racc::Parser
が、
class Foo < Bar
に
考えずに使うと、動かなくなりそう〜
これは将来の拡張のために用意したもので、現在指定する必然性はあまりありません。
と書いてあった。
!2007-12-11 Tue
確かに /*......*/ スタイルのコメントも使えた
!2007-12-10 Mon
header の代りに prepare が、 footer の代りに driver が、まだ使えた。
2.x からは廃止らしい(2.x なんて出るの?)。
!2007-12-09 Sun
* 「-v」オプション
* 「-E」オプション
* 「-c」オプション、説明だけじゃさっぱり分からず
ルールの最後の「;」は不要らしい。
確かにいままでルールの最後に「;」つけていなかった
!2007-12-08 Sat
「-g」なしありの差
***************
*** 128,134 ****
'line',
'a']
! Racc_debug_parser = false
##### racc system variables end #####
--- 128,134 ----
'line',
'a']
! Racc_debug_parser = true
##### racc system variables end #####
class Foo
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
| error EOL
a : 'a' { puts "*a*" }
end
---- inner
def initialize
@yydebug = $DEBUG
end
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
a
を入力して「-d」つきで起動すると、
reduce --> input
[ (input nil) ]
goto 1
[ 0 1 ]
read "a"("a") "a"
shift "a"
[ (input nil) ("a" "a") ]
goto 5
[ 0 1 5 ]
*a*
reduce "a" --> a
[ (input nil) (a "a") ]
goto 7
[ 0 1 7 ]
read :EOL(EOL) nil
shift EOL
[ (input nil) (a "a") (EOL nil) ]
goto 10
[ 0 1 7 10 ]
a
reduce a EOL --> line
[ (input nil) (line "a") ]
goto 6
[ 0 1 6 ]
reduce input line --> input
[ (input nil) ]
goto 1
[ 0 1 ]
read false($end) "$"
shift $end
[ (input nil) ($end "$") ]
goto 2
[ 0 1 2 ]
shift $end
[ (input nil) ($end "$") ($end "$") ]
goto 8
[ 0 1 2 8 ]
accept
!2007-12-07 Fri
header, inner, footer の確認
class Foo
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
| error EOL
a : 'a' { puts "*a*" }
end
---- header
#
# header
#
---- inner
#
# inner
#
---- footer
#
# footer
#
!2007-12-06 Thu
yyaccept
class Foo
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
| e EOL { puts "\t#{val[0]}" }
| error EOL
a : 'a' { puts "*a*" }
e : 'e' { puts "*e*"; yyaccept }
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
a
*a*
a
e
*e*
a
*a*
a
うーん、do_parse を抜けるという意味なのか???
上の do_parse を無効にして、下の do_parse を有効にして
a
e
a
を入力すると、
*a*
a
*e*
!2007-12-05 Wed
アクションの return
class Foo
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
| error EOL
a : 'a' { puts "*a*"; return ; puts "**a**" }
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
a
*a*
return するにしても、「return val[0]」が正しいのか???
または明示的に return で返した場合もこの値になります
という記述があった
!2007-12-04 Tue
「result = 〜」書かないと、どうなるか?とか
class Foo
rule
input :
| input line
line : EOL
| a EOL { puts "\t#{val[0]}" }
| error EOL
a : 'a'
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = Foo.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
a
a
a
a
bc
syntax error
b
a
a
なんで「b」「リターン」だと「syntax error」が表示されないんだっけ?
!2007-12-03 Mon
2007-08-16 Thu の bison マニュアルの多機能電卓、練習問題を
racc 本 01.first/intp.y を参考に racc 用に変更
2007-12-02 Sun との差分
***************
*** 62,67 ****
--- 63,69 ----
@sym = {}
init_table
+ init_const_table
end
def init_table
***************
*** 70,75 ****
--- 72,85 ----
end
end
+ def init_const_table
+ [[:PI, 3.14159265358979],
+ [:E, 2.71828182845905]].each do |n,v|
+ s = putsym(n, :VAR)
+ s[:VAL] = v
+ end
+ end
+
def putsym(sym_name, sym_type)
@sym[sym_name] = {:NAME => sym_name,
:TYPE => sym_type,
で、
E
2.71828182845905
PI
3.14159265358979
ln(E)
1.0
!2007-12-02 Sun
2007-08-14 Tue の bison マニュアルの多機能電卓を
racc 本 01.first/intp.y を参考に racc 用に変更
class RPN
prechigh
right '^'
left NEG
left '*' '/'
left '+' '-'
right '='
preclow
rule
input :
| input line
line : EOL
| exp EOL { puts "\t#{val[0]}" }
| error EOL
exp : NUM { result = val[0] }
| VAR { result = val[0][:VAL] }
| VAR '=' exp { result = val[2]; val[0][:VAL] = val[2] }
| FNCT '(' exp ')' { result = func(val[0][:NAME], val[2]) }
| exp '+' exp { result = val[0] + val[2] }
| exp '-' exp { result = val[0] - val[2] }
| exp '*' exp { result = val[0] * val[2] }
| exp '/' exp { result = val[0] / val[2] }
| '-' exp = NEG { result = -val[1] }
| exp '^' exp { result = val[0] ** val[2] }
| '(' exp ')' { result = val[1] }
end
---- inner
def initialize
@sym = {}
init_table
end
def init_table
[:sin, :cos, :atan, :ln, :exp, :sqrt].each do |f|
putsym(f, :FNCT)
end
end
def putsym(sym_name, sym_type)
@sym[sym_name] = {:NAME => sym_name,
:TYPE => sym_type,
:VAL => 0}
return @sym[sym_name]
end
def getsym(sym_name)
return @sym[sym_name]
end
def func(sym_name, arg)
case sym_name
when :sin
Math.sin(arg)
when :cos
Math.cos(arg)
when :ln
Math.log(arg)
when :exp
Math.exp(arg)
when :sqrt
Math.sqrt(arg)
end
end
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A[a-zA-Z_]\w*/
sym = $&.intern
s = getsym(sym)
unless s
s = putsym(sym, :VAR)
end
@q.push [ s[:TYPE], s ]
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = RPN.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
pi = 3.141592653589
3.141592653589
sin(pi)
7.93265789427594e-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.832909122935104
exp(ln(beta1))
2.3
4 + 4.5 - (34/(8*3+-3))
6.88095238095238
-56 + 2
-54.0
3 ^ 2
9.0
!2007-12-01 Sat
2007-08-12 Sun の bison マニュアルの中間記法電卓を
racc 本 01.first/intp.y を参考に racc 用に変更
class RPN
prechigh
right '^'
left UMINUS
left '*' '/'
left '+' '-'
preclow
rule
input :
| input line
line : EOL
| exp EOL { puts "\t#{val[0]}" }
| error EOL
exp : NUM { result = val[0] }
| exp '+' exp { result = val[0] + val[2] }
| exp '-' exp { result = val[0] - val[2] }
| exp '*' exp { result = val[0] * val[2] }
| exp '/' exp { result = val[0] / val[2] }
| '-' exp = UMINUS { result = -val[1] }
| exp '^' exp { result = val[0] ** val[2] }
| '(' exp ')' { result = val[1] }
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
do_parse
end
#do_parse
end
def next_token
@q.shift
end
def on_error( t, v, values )
STDERR.puts "syntax error"
end
---- footer
parser = RPN.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
4 + 4.5 - (34/(8*3+-3))
6.88095238095238
-56 + 2
-54.0
3 ^ 2
9.0
* 優先度の順番の記述の仕方が yacc と逆???
* UMINUS まわり、元が left だったので、nonassoc でなくそのままに
!2007-11-30 Fri
エラー処理について
yacc と同じように error というのはあるようだ
error を入れないと、
x
/usr/lib/ruby/1.8/racc/parser.rb:364:in `on_error': (Racc::ParseError)
parse error on value "x" (error) from /usr/lib/ruby/1.8/racc/parser.rb:102:in `_racc_do_parse_c'
以下のように error を入れると、
***************
*** 27,32 ****
--- 27,33 ----
line : EOL
| exp EOL { puts "\t#{val[0]}" }
+ | error EOL { yyerror }
exp : NUM { result = val[0] }
| exp exp '+' { result = val[0] + val[1] }
で、
4 9 +
13.0
x
4 9 +
13.0
「{ yyerror }」はなくても良いみたい
しかし、入力によってはダメ
n
/usr/lib/ruby/1.8/racc/parser.rb:364:in `on_error': (Racc::ParseError)
parse error on value "n" ("n") from /usr/lib/ruby/1.8/racc/parser.rb:102:in `_racc_do_parse_c'
kmyacc だと大丈夫だったのに…
例えば、2007-11-24 Sat の場合
n
syntax error
4 9 +
13
以下を追加
***************
*** 81,86 ****
--- 68,77 ----
@q.shift
end
+ def on_error( t, v, values )
+ STDERR.puts "syntax error"
+ end
+
---- footer
parser = RPN.new
で、
4 9+
13.0
x
4 9+
13.0
n
syntax error
4 9+
13.0
yyerror 相当ってことかな?
!2007-11-29 Thu
昨日のをちょっと変えて行ごとに値が出力されるように
違い
***************
*** 27,33 ****
| input line
line : EOL
! | exp EOL { puts val[0] }
exp : NUM { result = val[0] }
| exp exp '+' { result = val[0] + val[1] }
--- 26,32 ----
| input line
line : EOL
! | exp EOL { puts "\t#{val[0]}" }
exp : NUM { result = val[0] }
| exp exp '+' { result = val[0] + val[1] }
***************
*** 60,68 ****
line = $'
end
@q.push [ :EOL, nil ]
end
! do_parse
end
def next_token
--- 59,69 ----
line = $'
end
@q.push [ :EOL, nil ]
+
+ do_parse
end
! #do_parse
end
def next_token
で、
4 9 +
13.0
3 7 + 3 4 5 *+-
-13.0
3 7 + 3 4 5 * + - n
13.0
5 6 / 4 n +
-3.16666666666667
3 4 ^
81.0
1.2 3.4 +
4.6
0.2 3.4 +
3.6
1 3.4 +
4.4
!2007-11-28 Wed
2007-08-11 Sat の bison マニュアルの逆ポーランド記法電卓を
racc 本 01.first/intp.y を参考に racc 用に変更
class RPN
rule
input :
| input line
line : EOL
| exp EOL { puts val[0] }
exp : NUM { result = val[0] }
| exp exp '+' { result = val[0] + val[1] }
| exp exp '-' { result = val[0] - val[1] }
| exp exp '*' { result = val[0] * val[1] }
| exp exp '/' { result = val[0] / val[1] }
| exp exp '^' { result = val[0] ** val[1] }
| exp 'n' { result = -val[0] }
end
---- inner
def parse( f )
@q = []
f.each do |line|
line.strip!
until line.empty? do
case line
when /\A\s+/, /\A\#.*/
;
when /\A\d+(\.\d+)*/
@q.push [ :NUM, $&.to_f ]
when /\A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
end
do_parse
end
def next_token
@q.shift
end
---- footer
parser = RPN.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
で、
4 9 +
3 7 + 3 4 5 *+-
3 7 + 3 4 5 * + - n
5 6 / 4 n +
3 4 ^
1.2 3.4 +
0.2 3.4 +
1 3.4 +
を入力すると、
13.0
-13.0
13.0
-3.16666666666667
81.0
4.6
3.6
4.4
* EOL が '\n' だとエラー
* EOL が "\n" なら OK
!2007-11-27 Tue
2007-08-16 Thu の bison マニュアルの多機能電卓、練習問題を
kmyacc のサンプル calc.ply を参考に Perl 用に変更
2007-11-26 Mon との違い
***************
*** 75,80 ****
--- 75,84 ----
foreach my $x ("sin", "cos", "atan", "ln", "exp", "sqrt") {
putsym($x, $FNCT);
}
+
+ my $s;
+ $s = putsym("PI", $VAR); $s->{'val'} = 3.14159265358979;
+ $s = putsym("E", $VAR); $s->{'val'} = 2.71828182845905;
}
sub putsym
で、
PI
3.14159265358979
E
2.71828182845905
sin(PI/2)
1
!2007-11-26 Mon
2007-08-14 Tue の bison マニュアルの多機能電卓を
kmyacc のサンプル calc.ply を参考に Perl 用に変更
%{
%}
%token NUM
%token VAR FNCT
%right '='
%left '-' '+'
%left '*' '/'
%left NEG /* 否定 -- 単項の負 */
%right '^' /* べき乗 */
/* 文法が続く */
%%
input: /* 空 */
| input line
;
line:
'\n'
| exp '\n' { print exp, "\n"; }
| error '\n'
;
result@exp: NUM { result = NUM; }
| VAR { result = VAR->{'val'}; }
| VAR '=' a@exp { result = a; VAR->{'val'} = a; }
| FNCT '(' a@exp ')' { result = func(FNCT->{'name'}, a); }
| a@exp '+' b@exp { result = a + b; }
| a@exp '-' b@exp { result = a - b; }
| a@exp '*' b@exp { result = a * b; }
| a@exp '/' b@exp { result = a / b; }
| '-' a@exp %prec NEG { result = -a; }
| a@exp '^' b@exp { result = a ** b; }
| '(' a@exp ')' { result = a; }
;
/* 文法の終わり */
%%
$lexbuf = '';
%sym = ();
sub init_table
{
foreach my $x ("sin", "cos", "atan", "ln", "exp", "sqrt") {
putsym($x, $FNCT);
}
}
sub putsym
{
my ($sym_name, $sym_type) = @_;
$sym{$sym_name} = {'name' => $sym_name,
'type' => $sym_type,
'val' => 0};
return $sym{$sym_name};
}
sub getsym
{
my ($sym_name) = @_;
if (exists($sym{$sym_name})) {
return $sym{$sym_name};
} else {
return 0;
}
}
sub func
{
my ($sym_name, $v) = @_;
if ($sym_name eq "sin") {
return sin($v);
} elsif ($sym_name eq "cos") {
return cos($v);
} elsif ($sym_name eq "atan") {
return atan($v);
} elsif ($sym_name eq "ln") {
return log($v);
} elsif ($sym_name eq "exp") {
return exp($v);
} elsif ($sym_name eq "sqrt") {
return sqrt($v);
} else {
return 0;
}
}
sub yylex
{
while (1) {
if ($lexbuf =~ /^([\t ]+)/) {
$lexbuf = substr($lexbuf, length($1));
}
last if ($lexbuf ne '');
if (!($lexbuf = )) {
return 0;
}
}
if ($lexbuf =~ /^(\d+(\.\d+)*)/) {
$yylval = $1 - 0;
$lexbuf = substr($lexbuf, length($1));
return $NUM;
} elsif ($lexbuf =~ /^([a-zA-Z]+[a-zA-Z0-9_]*)/) {
my $sym = $1;
$lexbuf = substr($lexbuf, length($1));
my $s = getsym($sym);
if (ref($s) ne 'HASH') {
$s = putsym($sym, $VAR);
}
$yylval = $s;
return $s->{'type'};
} else {
my $ret = ord($lexbuf);
$lexbuf = substr($lexbuf, 1);
return $ret;
}
}
sub yyerror
{
my ($msg) = @_;
print "$msg\n";
}
init_table();
exit &yyparse();
で、
pi = 3.141592653589
3.141592653589
sin(pi)
7.93265789427594e-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.832909122935104
exp(ln(beta1))
2.3
4 + 4.5 - (34/(8*3+-3))
6.88095238095238
-56 + 2
-54
3 ^ 2
9
リファレンスの使い方で、ちょっと迷っちゃったよ…
!2007-11-25 Sun
2007-08-12 Sun の bison マニュアルの中間記法電卓を
kmyacc のサンプル calc.ply を参考に Perl 用に変更
/* BISON宣言 */
%token NUM
%left '-' '+'
%left '*' '/'
%left NEG /* negation--単項マイナス */
%right '^' /* べき乗関数 */
/* 文法規則が続く */
%%
input: /* 空文字列 */
| input line
;
line: '\n'
| exp '\n' { print exp, "\n"; }
| error '\n'
;
result@exp: NUM { result = NUM; }
| a@exp '+' b@exp { result = a + b; }
| a@exp '-' b@exp { result = a - b; }
| a@exp '*' b@exp { result = a * b; }
| a@exp '/' b@exp { result = a / b; }
| '-' a@exp %prec NEG { result = - a; }
| a@exp '^' b@exp { result = a ** b; }
| '(' a@exp ')' { result = a; }
;
%%
$lexbuf = '';
sub yylex
{
while (1) {
if ($lexbuf =~ /^([\t ]+)/) {
$lexbuf = substr($lexbuf, length($1));
}
last if ($lexbuf ne '');
if (!($lexbuf = )) {
return 0;
}
}
if ($lexbuf =~ /^(\d+(\.\d+)*)/) {
$yylval = $1 - 0;
$lexbuf = substr($lexbuf, length($1));
return $NUM;
} else {
my $ret = ord($lexbuf);
$lexbuf = substr($lexbuf, 1);
return $ret;
}
}
sub yyerror
{
my ($msg) = @_;
print "$msg\n";
}
exit &yyparse();
で、
4 + 4.5 - (34/(8*3+-3))
6.88095238095238
-56 + 2
-54
3 ^ 2
9
x
syntax error
4 + 4.5 - (34/(8*3+-3))
6.88095238095238
!2007-11-24 Sat
2007-08-11 Sat の bison マニュアルの逆ポーランド記法電卓を
kmyacc のサンプル calc.ply を参考に Perl 用に変更
%token NUM
%%
input: /* 空 */
| input line
;
line: '\n'
| exp '\n' { print exp, "\n"; }
| error '\n'
;
result@exp: NUM { result = NUM; }
| a@exp b@exp '+' { result = a + b; }
| a@exp b@exp '-' { result = a - b; }
| a@exp b@exp '*' { result = a * b; }
| a@exp b@exp '/' { result = a / b; }
| a@exp b@exp '^' { result = a ** b; }
| a@exp 'n' { result = -a; }
;
%%
$lexbuf = '';
sub yylex
{
while (1) {
if ($lexbuf =~ /^([\t ]+)/) {
$lexbuf = substr($lexbuf, length($1));
}
last if ($lexbuf ne '');
if (!($lexbuf = )) {
print "return 0\n";
return 0;
}
}
if ($lexbuf =~ /^(\d+(\.\d+)*)/) {
$yylval = $1 - 0;
$lexbuf = substr($lexbuf, length($1));
return $NUM;
} else {
my $ret = ord($lexbuf);
$lexbuf = substr($lexbuf, 1);
return $ret;
}
}
sub yyerror
{
my ($msg) = @_;
print "$msg\n";
}
exit &yyparse();
で、
4 9 +
13
3 7 + 3 4 5 *+-
-13
3 7 + 3 4 5 * + - n
13
5 6 / 4 n +
-3.16666666666667
3 4 ^
81
1.2 3.4 +
4.6
0.2 3.4 +
3.6
1 3.4 +
4.4
return 0
サンプルの calc.ply は
if ($lexbuf =~ /^[\t ]+/) {
が
if ($lexbuf =~ /^([\t ]+)/) {
の間違いのようだ〜。そうでないと、空白がうまく読み飛ばされない
!2007-11-23 Fri
2007-11-19 Mon の bison マニュアルの多機能電卓を jflex を使って
2007-08-09 Thu のコードをかなり利用
lex ファイルは、
%%
%{
private Calc yyparser;
public Object yylval;
public Lexer(java.io.Reader r, Calc yyparser) {
this(r);
this.yyparser = yyparser;
}
%}
%class Lexer
%unicode
%line
%column
%byaccj
%%
[\t ]* { }
[0-9]+ { yylval = new Double(yytext()); return yyparser.NUM; }
[0-9]+\.[0-9]+ { yylval = new Double(yytext()); return yyparser.NUM; }
[a-zA-Z][a-zA-Z0-9]* {
C20071123_kmyacc00 s = yyparser.getsym(yytext());
if (s == null) {
s = yyparser.putsym(yytext(), yyparser.VAR);
}
yylval = s;
return s.type;
}
\n|. { return(yytext().charAt(0)); }
Calc.jy は、
%{
import java.io.*;
import java.util.*;
class C20071123_kmyacc00 {
public String name;
public int type;
public double val;
C20071123_kmyacc00(String s, int t, double v) {
name = s; type = t; val = v;
}
}
%}
%token NUM
%type exp NUM
%token VAR FNCT /* 変数と関数 */
%right '='
%left '-' '+'
%left '*' '/'
%left NEG /* 否定 -- 単項の負 */
%right '^' /* べき乗 */
/* 文法が続く */
%%
input: /* 空 */
| input line
;
line:
'\n'
| exp '\n' { System.out.println("\t" + $1); }
| error '\n'
;
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 final VAR = 0;
//private final FNCT = 1;
private int ch = 0;
private static Map sym = new HashMap();
//private C20071123_kmyacc00 yylval;
private static void init_table() {
putsym("sin", FNCT);
putsym("cos", FNCT);
putsym("atan", FNCT);
putsym("ln", FNCT);
putsym("exp", FNCT);
putsym("sqrt", FNCT);
}
public static C20071123_kmyacc00 putsym(String sym_name, int sym_type) {
C20071123_kmyacc00 x = new C20071123_kmyacc00(sym_name, sym_type, 0);
sym.put(sym_name, x);
return x;
}
public static C20071123_kmyacc00 getsym(String sym_name) {
if (sym.containsKey(sym_name)) {
return (C20071123_kmyacc00)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;
}
}
private Lexer lexer;
int yylex() {
int r = -1;
try {
r = lexer.yylex();
yylval = lexer.yylval;
} catch (IOException e) {
System.err.println("IO error :"+e);
}
return r;
}
void yyerror(String msg)
{
System.err.println(msg);
}
public Calc() {
lexer = new Lexer(new InputStreamReader(System.in), this);
}
public static void main(String args[]) {
// yydebug = true;
// yyDumpParseTree = true;
init_table();
Calc it = new Calc();
it.yyparse();
}
で、
pi = 3.141592653589
3.141592653589
sin(pi)
7.932657934721266E-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.832909122935104
exp(ln(beta1))
2.3
!2007-11-22 Thu
2007-11-18 Sun の bison マニュアルの中間記法電卓を jflex を使って
2007-08-09 Thu のコードをかなり利用
lex ファイルは 2007-11-21 Wed とほとんど同じだが、
%%
%{
private Calc yyparser;
public Object yylval;
public Lexer(java.io.Reader r, Calc yyparser) {
this(r);
this.yyparser = yyparser;
}
%}
%class Lexer
%unicode
%line
%column
%byaccj
%%
[0-9]+ { yylval = new Double(yytext()); return yyparser.NUM; }
[0-9]+\.[0-9]+ { yylval = new Double(yytext()); return yyparser.NUM; }
[\t ]* { }
\n|. { return(yytext().charAt(0)); }
Calc.jy は、
%{
import java.io.*;
%}
/* BISON宣言 */
%token NUM
%type exp NUM
%left '-' '+'
%left '*' '/'
%left NEG /* negation--単項マイナス */
%right '^' /* べき乗関数 */
/* 文法規則が続く */
%%
input: /* 空文字列 */
| input line
;
line: '\n'
| exp '\n' { System.out.println("\t" + $1); }
| error '\n' { yyerrflag = 0; }
;
exp: NUM { $$ = new Double($1.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 Lexer lexer;
int yylex() {
int r = -1;
try {
r = lexer.yylex();
yylval = lexer.yylval;
} catch (IOException e) {
System.err.println("IO error :"+e);
}
return r;
}
void yyerror(String msg)
{
System.err.println(msg);
}
public Calc() {
lexer = new Lexer(new InputStreamReader(System.in), this);
}
public static void main(String args[]) {
// yydebug = true;
// yyDumpParseTree = true;
Calc it = new Calc();
it.yyparse();
}
で、
4 + 4.5 - (34/(8*3+-3))
6.880952380952381
-56 + 2
-54.0
3 ^ 2
9.0
a
syntax error
1+2
3.0
!2007-11-21 Wed
2007-11-16 Fri の bison マニュアルの逆ポーランド記法電卓を jflex を使って
2007-08-09 Thu のコードをかなり利用
lex ファイルは、
%%
%{
private Calc yyparser;
public Object yylval;
public Lexer(java.io.Reader r, Calc yyparser) {
this(r);
this.yyparser = yyparser;
}
%}
%class Lexer
%unicode
%line
%column
%byaccj
%%
[0-9]+ { yylval = new Double(yytext()); return yyparser.NUM; }
[0-9]+\.[0-9]+ { yylval = new Double(yytext()); return yyparser.NUM; }
[\t ]* { }
[\n\^n+*/-] { return(yytext().charAt(0)); }
. { System.err.println("Illegal input"); }
Calc.jy は、
%{
import java.io.*;
%}
%token NUM
%type exp NUM
%%
input: /* 空 */
| input line
;
line: '\n'
| exp '\n' { System.out.println("\t" + $1); }
;
exp: NUM { $$ = new Double($1.doubleValue()); }
| exp exp '+' { $$ = new Double($1.doubleValue() + $2.doubleValue()); }
| exp exp '-' { $$ = new Double($1.doubleValue() - $2.doubleValue()); }
| exp exp '*' { $$ = new Double($1.doubleValue() * $2.doubleValue()); }
| exp exp '/' { $$ = new Double($1.doubleValue() / $2.doubleValue()); }
/* べき乗関数 */
| exp exp '^' { $$ = new Double(Math.pow($1.doubleValue(), $2.doubleValue())); }
/* 単項のマイナス */
| exp 'n' { $$ = new Double(-$1.doubleValue()); }
;
%%
private Lexer lexer;
int yylex() {
int r = -1;
try {
r = lexer.yylex();
yylval = lexer.yylval;
} catch (IOException e) {
System.err.println("IO error :"+e);
}
return r;
}
void yyerror(String msg)
{
System.err.println(msg);
}
public Calc() {
lexer = new Lexer(new InputStreamReader(System.in), this);
}
public static void main(String args[]) {
// yydebug = true;
// yyDumpParseTree = true;
Calc it = new Calc();
it.yyparse();
}
で、
4 9 +
13.0
3 7 + 3 4 5 *+-
-13.0
3 7 + 3 4 5 * + - n
13.0
5 6 / 4 n +
-3.1666666666666665
3 4 ^
81.0
1.2 3.4 +
4.6
0.2 3.4 +
3.6
.2 3.4 +
Illegal input
5.4
1. 3.4 +
Illegal input
4.4
1 3.4 +
4.4
* 「[\n.]」だとダメだった。[] の中には「.」を書いてもダメなのかな?というかメタじゃない「.」という意味になるのかな?
* 「\n|.」だと OK だった
!2007-11-20 Tue
2007-08-16 Thu の bison マニュアルの多機能電卓、練習問題を
kmyacc のサンプル Calc.jy を参考に Java 用に変更
2007-11-19 Mon との差
***************
*** 88,93 ****
--- 98,107 ----
putsym("ln", FNCT);
putsym("exp", FNCT);
putsym("sqrt", FNCT);
+
+ C20071119_kmyacc00 x;
+ x = new C20071119_kmyacc00("PI", VAR, 3.14159265358979); sym.put("PI", x);
+ x = new C20071119_kmyacc00("E", VAR, 2.71828182845905); sym.put("E", x);
}
private static C20071119_kmyacc00 putsym(String sym_name, int sym_type) {
で、
pi = 3.141592653589
3.141592653589
sin(pi)
7.932657934721266E-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.832909122935104
exp(ln(beta1))
2.3
PI
3.14159265358979
PI * 2
6.28318530717958
E
2.71828182845905
ln(E)
1.0000000000000018
!2007-11-19 Mon
2007-08-14 Tue の bison マニュアルの多機能電卓を
kmyacc のサンプル Calc.jy を参考に Java 用に変更
%{
import java.util.*;
class C20071119_kmyacc00 {
public String name;
public int type;
public double val;
C20071119_kmyacc00(String s, int t, double v) {
name = s; type = t; val = v;
}
}
%}
%token NUM
%type exp NUM
%token VAR FNCT /* 変数と関数 */
%right '='
%left '-' '+'
%left '*' '/'
%left NEG /* 否定 -- 単項の負 */
%right '^' /* べき乗 */
/* 文法が続く */
%%
input: /* 空 */
| input line
;
line:
'\n'
| exp '\n' { System.out.println("\t" + $1); }
| error '\n'
;
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 final VAR = 0;
//private final FNCT = 1;
private int ch = 0;
private static Map sym = new HashMap();
//private C20071119_kmyacc00 yylval;
private static void init_table() {
putsym("sin", FNCT);
putsym("cos", FNCT);
putsym("atan", FNCT);
putsym("ln", FNCT);
putsym("exp", FNCT);
putsym("sqrt", FNCT);
}
private static C20071119_kmyacc00 putsym(String sym_name, int sym_type) {
C20071119_kmyacc00 x = new C20071119_kmyacc00(sym_name, sym_type, 0);
sym.put(sym_name, x);
return x;
}
private C20071119_kmyacc00 getsym(String sym_name) {
if (sym.containsKey(sym_name)) {
return (C20071119_kmyacc00)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;
}
}
private int getch() {
int c = ch;
if (c != 0) {
ch = 0;
return c;
}
try {
return System.in.read();
} catch (java.io.IOException e) {
throw new Error(e.getMessage());
}
}
private void ungetch(int c) { ch = c; }
int yylex() {
yylval = null;
int n = 0;
char[] buf = new char[100];
for (;;) {
int c = getch();
if (c < 0)
return 0;
else if (c == ' ' || c == '\t')
;
else if (Character.isDigit((char)c) || c == '.') {
while (Character.isDigit((char)c) || c == '.') {
buf[n++] = (char)c;
if (c == '.') break;
c = getch();
}
if (c == '.') {
c = getch();
while (Character.isDigit((char)c)) {
buf[n++] = (char)c;
c = getch();
}
}
ungetch(c);
if (n == 1 && buf[0] == '.') {
return '.';
} else {
yylval = new Double(new String(buf, 0, n));
return NUM;
}
} else if (Character.isJavaIdentifierStart((char)c)) {
buf[n++] = (char)c;
c = getch();
while (Character.isJavaIdentifierPart((char)c)) {
buf[n++] = (char)c;
c = getch();
}
ungetch(c);
String sym = new String(buf, 0, n);
C20071119_kmyacc00 s = getsym(sym);
if (s == null) {
s = putsym(sym, VAR);
}
yylval = s;
return s.type;
}
else
return c;
}
}
void yyerror(String msg)
{
System.err.println(msg);
}
public static void main(String args[]) {
// yydebug = true;
// yyDumpParseTree = true;
init_table();
Calc it = new Calc();
it.yyparse();
}
で、
pi = 3.141592653589
3.141592653589
sin(pi)
7.932657934721266E-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.832909122935104
exp(ln(beta1))
2.3
* Java 分かってないなあ〜。static をつけないとアクセスできなかったり。場当たり的に変更…
!2007-11-18 Sun
2007-08-13 Mon の bison マニュアルの中間記法電卓、エラー処理入りを
kmyacc のサンプル Calc.jy を参考に Java 用に変更
2007-11-17 Sat との差
***************
*** 34,40 ****
;
line: '\n'
! | exp '\n' { System.out.println($1); }
;
exp: NUM { $$ = new Double($1.doubleValue()); }
--- 39,46 ----
;
line: '\n'
! | exp '\n' { System.out.println($1); }
! | error '\n' { yyerrflag = 0; }
;
exp: NUM { $$ = new Double($1.doubleValue()); }
で、
4 + 4.5 - (34/(8*3+-3))
6.880952380952381
-56 + 2
-54.0
3 ^ 2
9.0
a
syntax error
1+2
3.0
!2007-11-17 Sat
2007-08-12 Sun の bison マニュアルの中間記法電卓を
kmyacc のサンプル Calc.jy を参考に Java 用に変更
二番目の %% 以降の lex と main 部は 2007-11-16 Fri と同じなので省略
%{
%}
/* BISON宣言 */
%token NUM
%type exp NUM
%left '-' '+'
%left '*' '/'
%left NEG /* negation--単項マイナス */
%right '^' /* べき乗関数 */
/* 文法規則が続く */
%%
input: /* 空文字列 */
| input line
;
line: '\n'
| exp '\n' { System.out.println($1); }
;
exp: NUM { $$ = new Double($1.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()); }
;
%%
で、
4 + 4.5 - (34/(8*3+-3))
6.880952380952381
-56 + 2
-54.0
3 ^ 2
9.0
!2007-11-16 Fri
2007-08-11 Sat の bison マニュアルの逆ポーランド記法電卓を
kmyacc のサンプル Calc.jy を参考に Java 用に変更
%{
%}
%token NUM
%type exp NUM
%%
input: /* 空 */
| input line
;
line: '\n'
| exp '\n' { System.out.println($1); }
;
exp: NUM { $$ = new Double($1.doubleValue()); }
| exp exp '+' { $$ = new Double($1.doubleValue() + $2.doubleValue()); }
| exp exp '-' { $$ = new Double($1.doubleValue() - $2.doubleValue()); }
| exp exp '*' { $$ = new Double($1.doubleValue() * $2.doubleValue()); }
| exp exp '/' { $$ = new Double($1.doubleValue() / $2.doubleValue()); }
/* べき乗関数 */
| exp exp '^' { $$ = new Double(Math.pow($1.doubleValue(), $2.doubleValue())); }
/* 単項のマイナス */
| exp 'n' { $$ = new Double(-$1.doubleValue()); }
;
%%
private int ch = 0;
private int getch() {
int c = ch;
if (c != 0) {
ch = 0;
return c;
}
try {
return System.in.read();
} catch (java.io.IOException e) {
throw new Error(e.getMessage());
}
}
private void ungetch(int c) { ch = c; }
int yylex() {
yylval = null;
for (;;) {
int c = getch();
if (c < 0)
return 0;
else if (c == ' ' || c == '\t')
;
else if (Character.isDigit((char)c) || c == '.') {
int n = 0;
char[] buf = new char[100];
while (Character.isDigit((char)c) || c == '.') {
buf[n++] = (char)c;
if (c == '.') break;
c = getch();
}
if (c == '.') {
c = getch();
while (Character.isDigit((char)c)) {
buf[n++] = (char)c;
c = getch();
}
}
ungetch(c);
if (n == 1 && buf[0] == '.') {
return '.';
} else {
yylval = new Double(new String(buf, 0, n));
return NUM;
}
}
else
return c;
}
}
void yyerror(String msg)
{
System.err.println(msg);
}
public static void main(String args[]) {
// yydebug = true;
// yyDumpParseTree = true;
Calc it = new Calc();
it.yyparse();
}
で、
4 9 +
13.0
3 7 + 3 4 5 *+-
-13.0
3 7 + 3 4 5 * + - n
13.0
5 6 / 4 n +
-3.1666666666666665
3 4 ^
81.0
1.2 3.4 +
4.6
0.2 3.4 +
3.6
.2 3.4 +
3.6
1. 3.4 +
4.4
1 3.4 +
4.4
!2007-11-15 Thu
デバッグ
2007-10-27 Sat のコードを使用
コンパイル時「-DYYDEBUG=1」をつけて
abc
def
を入力すると、
%% State 0, Lookahead --none--
%% Reduce by (1) input : /* empty */
%% State 1, Lookahead --none--
%% Reading 'a'
%% Shift 'a'
%% State 2, Lookahead --none--
%% Reading 'b'
%% Shift 'b'
%% State 4, Lookahead --none--
%% Reading 'c'
%% Shift 'c'
%% State 6, Lookahead --none--
%% Reading '\n'
%% Shift '\n'
%% Reduce by (3) line : 'a' 'b' 'c' '\n'
*abc*
%% Reduce by (2) input : input line
%% State 1, Lookahead --none--
%% Reading 'd'
%% Shift 'd'
%% State 3, Lookahead --none--
%% Reading 'e'
%% Shift 'e'
%% State 5, Lookahead --none--
%% Reading 'f'
%% Shift 'f'
%% State 7, Lookahead --none--
%% Reading '\n'
%% Shift '\n'
%% Reduce by (4) line : 'd' 'e' 'f' '\n'
*def*
%% Reduce by (2) input : input line
%% State 1, Lookahead --none--
%% Reading $EOF
%% Accepted.
!2007-11-14 Wed
還元/還元衝突
2007-10-15 Mon のコードを使用
以下のメッセージ
2 rule(s) never reduced
20071113_kmyacc00.y: there are 4 shift/reduce conflicts
!2007-11-13 Tue
あるマクロ
#define yyclearin (yychar = -1)
#define yyerrok (yyerrflag = 0)
#define YYRECOVERING (yyerrflag != 0)
#define YYACCEPT return (0)
#define YYABORT return (1)
#define YYERROR goto yyerrlab
#ifndef YYMAXDEPTH
# define YYMAXDEPTH 512
#endif /* !YYMAXDEPTH */
ないマクロ
* YYEMPTY
* YYINITDEPTH
* YYPRINT
!2007-11-12 Mon
再入可能構文解析器
2007-09-30 Sun のコードを使用
1
を入力すると、
1
1 10
!2007-11-11 Sun
ちょっと道草
2007-08-14 Tue, 2007-11-02 Fri の bison マニュアルの多機能電卓で flex を使用
lex ファイル(2007-03-22 Thu の flex の expr.lex を改造)
%{
#include "20070814_bison00.h"
#include "y.tab.h"
void yyerror(char *s);
%}
%%
[ \t]+
[0-9]+ { yylval.val = atof(yytext);
return(NUM);
}
[0-9]+\.[0-9]+ {
sscanf(yytext, "%lf", &yylval.val);
return(NUM);
}
[a-zA-Z][a-zA-Z0-9]* {
static symrec *s;
s = getsym(yytext);
if (s == 0) {
s = putsym(yytext, VAR);
}
yylval.tptr = s;
return s->type;
}
\n return '\n';
. { return(yytext[0]); }
%%
yacc ファイル
%{
#include
#include
#include
#include
#include /* cos(), sin()などの数学関数のため */
//#include "calc.h" /* `symrec'の定義を含む */
#include "20070814_bison00.h"
void yyerror(char *s);
int yylex(void);
void init_table(void);
int yyparse(void);
%}
%union {
double val; /* 数値を返すため */
symrec *tptr; /* 記号表へのポインタを返すため */
}
%token NUM /* 単純な倍精度数値 */
%token VAR FNCT /* 変数と関数 */
%type exp
%right '='
%left '-' '+'
%left '*' '/'
%left NEG /* 否定 -- 単項の負 */
%right '^' /* べき乗 */
/* 文法が続く */
%%
input: /* 空 */
| input line
;
line:
'\n'
| exp '\n' { printf ("\t%.10g\n", $1); }
| error '\n' { yyerrok; }
;
exp: NUM { $$ = $1; }
| VAR { $$ = $1->value.var; }
| VAR '=' exp { $$ = $3; $1->value.var = $3; }
| FNCT '(' exp ')' { $$ = (*($1->value.fnctptr))($3); }
| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 - $3; }
| exp '*' exp { $$ = $1 * $3; }
| exp '/' exp { $$ = $1 / $3; }
| '-' exp %prec NEG { $$ = -$2; }
| exp '^' exp { $$ = pow ($1, $3); }
| '(' exp ')' { $$ = $2; }
;
/* 文法の終わり */
%%
#include
int main ()
{
init_table();
return yyparse();
}
void yyerror (s) /* エラーがあるとyyparseから呼び出される */
char *s;
{
printf("%s\n", s);
}
struct init
{
char *fname;
double (*fnct)();
};
struct init arith_fncts[]
= {
"sin", sin,
"cos", cos,
"atan", atan,
"ln", log,
"exp", exp,
"sqrt", sqrt,
0, 0
};
/* 記号表:`struct symrec'のリスト */
symrec *sym_table = (symrec *)0;
void init_table(void) /* 数学関数を表に登録する */
{
int i;
symrec *ptr;
for (i = 0; arith_fncts[i].fname != 0; i++)
{
ptr = putsym(arith_fncts[i].fname, FNCT);
ptr->value.fnctptr = arith_fncts[i].fnct;
}
}
symrec *
putsym (sym_name,sym_type)
char *sym_name;
int sym_type;
{
symrec *ptr;
ptr = (symrec *) malloc (sizeof (symrec));
ptr->name = (char *) malloc (strlen (sym_name) + 1);
strcpy (ptr->name,sym_name);
ptr->type = sym_type;
ptr->value.var = 0; /* 関数の場合にも値を0にする */
ptr->next = (struct symrec *)sym_table;
sym_table = ptr;
return ptr;
}
symrec *
getsym (sym_name)
char *sym_name;
{
symrec *ptr;
for (ptr = sym_table; ptr != (symrec *) 0;
ptr = (symrec *)ptr->next)
if (strcmp (ptr->name,sym_name) == 0)
return ptr;
return 0;
}
で、
pi = 3.141592653589
3.141592654
sin(pi)
7.932657894e-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.8329091229
exp(ln(beta1))
2.3
* 「\n return '\n';」を入れないとうまく動かなかった
!2007-11-10 Sat
ちょっと道草
2007-08-11 Sat, 2007-10-30 Tue の
bison マニュアルの逆ポーランド記法電卓で flex を使用
lex ファイル(2007-03-22 Thu の flex の expr.lex を改造)
%{
#define YYSTYPE double
#include "y.tab.h"
void yyerror(char *s);
%}
%%
[ \t]+
[0-9]+ { yylval = atof(yytext);
return(NUM);
}
[0-9]+\.[0-9]+ {
sscanf(yytext, "%lf", &yylval);
return(NUM);
}
"+" return(PLUS);
"-" return(MINUS);
"*" return(MULT);
"/" return(DIV);
"^" return(EXPON);
"n" return(UMINUS);
\n return(EOL);
. { yyerror("Illegal character");
return(EOL);
}
%%
yacc ファイル
%{
#define YYSTYPE double
#include
#include
#include
void yyerror(char *s);
int yylex(void);
int yyparse(void);
%}
%token NUM
%token PLUS MINUS MULT DIV EXPON UMINUS
%token EOL
%%
input: /* 空 */
| input line
;
line: EOL
| exp EOL { printf ("\t%.10g\n", $1); }
;
exp: NUM { $$ = $1; }
| exp exp PLUS { $$ = $1 + $2; }
| exp exp MINUS { $$ = $1 - $2; }
| exp exp MULT { $$ = $1 * $2; }
| exp exp DIV { $$ = $1 / $2; }
/* べき乗関数 */
| exp exp EXPON { $$ = pow ($1, $2); }
/* 単項のマイナス */
| exp UMINUS { $$ = -$1; }
;
%%
void yyerror (char *s)
{
printf ("%s\n", s);
}
int main()
{
return yyparse();
}
で、
4 9 +
13
3 7 + 3 4 5 *+-
-13
3 7 + 3 4 5 * + - n
13
5 6 / 4 n +
-3.166666667
3 4 ^
81
!2007-11-09 Fri
「%pure_parser」
2007-08-11 Sat の bison マニュアルの逆ポーランド記法電卓を利用
2007-10-30 Tue のコードとの差
***************
*** 25,34 ****
#include
#include
void yyerror(char *s);
! int yylex(void);
%}
%token NUM
%%
--- 26,40 ----
#include
#include
+ #define YYLEXARGS YYSTYPE *yylvalp
+ #define YYLVAL (*yylvalp)
+
void yyerror(char *s);
! int yylex(YYLEXARGS);
%}
+ %pure_parser
+
%token NUM
%%
***************
*** 58,64 ****
printf ("%s\n", s);
}
! int yylex ()
{
int c;
--- 64,70 ----
printf ("%s\n", s);
}
! int yylex (YYLEXARGS)
{
int c;
***************
*** 69,75 ****
if (c == '.' || isdigit (c))
{
ungetc (c, stdin);
! scanf ("%lf", &yylval);
return NUM;
}
/* ファイルの終わりを処理する */
--- 75,81 ----
if (c == '.' || isdigit (c))
{
ungetc (c, stdin);
! scanf ("%lf", &YYLVAL);
return NUM;
}
/* ファイルの終わりを処理する */
(yylex の宣言を書きつつ)「#if YYPURE」をうまい位置に書く方法が
良く分からなかった。
「#define YYPURE 1」が「%{%}」の中身より後になってしまうため。
!2007-11-08 Thu
2007-09-27 Thu の「@数字」が使えるか確認
コンパイラでエラーが。ダメなのかな???
!2007-11-07 Wed
名前による参照(-n オプションが必要)
2007-08-11 Sat の bison マニュアルの逆ポーランド記法電卓
一部だけ
input: /* 空 */
| input line
;
line: '\n'
| exp '\n' { printf ("\t%.10g\n", exp); }
;
r@exp: NUM { r = $1; }
| s1@exp s2@exp '+' { r = s1 + s2; }
| t1@exp t2@exp '-' { r = t1 - t2; }
| u1@exp u2@exp '*' { r = u1 * u2; }
| v1@exp v2@exp '/' { r = v1 / v2; }
/* べき乗関数 */
| w1@exp w2@exp '^' { r = pow (w1, w2); }
/* 単項のマイナス */
| x1@exp 'n' { r = -x1; }
;
!2007-11-06 Tue
名前による参照
2007-08-11 Sat の bison マニュアルの逆ポーランド記法電卓
一部だけ
input: /* 空 */
| input line
;
line: '\n'
| exp '\n' { printf ("\t%.10g\n", exp); }
;
r@exp: NUM { r = $1; }
| s1@exp s2@exp '+' { r = s1 + s2; }
| s1@exp s2@exp '-' { r = s1 - s2; }
| s1@exp s2@exp '*' { r = s1 * s2; }
| s1@exp s2@exp '/' { r = s1 / s2; }
/* べき乗関数 */
| s1@exp s2@exp '^' { r = pow (s1, s2); }
/* 単項のマイナス */
| s1@exp 'n' { r = -s1; }
;
* -n オプションが必要
* NUM の部分をどう書けば良いか不明。とりあえず $1 のままにしておいた。「r = NUM;」で大丈夫なのかな?
!2007-11-05 Mon
2007-08-17 Fri の bison マニュアルの多機能電卓 練習問題3
そのまま使用可能だった。
だが、そもそものプログラムがまずかった???
pi = 3.141592653589
Unkown variable pi
3.141592654
sin(pi)
7.932657894e-13
alpha = beta1 = 2.3
Unkown variable alpha
Unkown variable beta1
2.3
alpha
2.3
ln(alpha)
0.8329091229
exp(ln(beta1))
2.3
x
Unkown variable x
0
x + 1
1
!2007-11-04 Sun
2007-08-16 Thu の bison マニュアルの多機能電卓 練習問題2
そのまま使用可能だった
pi = 3.141592653589
3.141592654
sin(pi)
7.932657894e-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.8329091229
exp(ln(beta1))
2.3
PI
3.141592654
PI * 2
6.283185307
E
2.718281828
ln(E)
1
!2007-11-03 Sat
2007-08-15 Wed の bison マニュアルの多機能電卓 練習問題1
そのまま使用可能だった
pi = 3.141592653589
3.141592654
sin(pi)
7.932657894e-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.8329091229
exp(ln(beta1))
2.3
ceil(1.2)
2
ceil(-1.2)
-1
!2007-11-02 Fri
2007-08-14 Tue の bison マニュアルの多機能電卓
そのまま使用可能だった
pi = 3.141592653589
3.141592654
sin(pi)
7.932657894e-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.8329091229
exp(ln(beta1))
2.3
!2007-11-01 Thu
2007-08-13 Mon の bison マニュアルの中間記法電卓、エラー処理入り
そのまま使用可能だった
4 + 4.5 - (34/(8*3+-3))
6.880952381
-56 + 2
-54
3 ^ 2
9
a
syntax error
1+2
3
!2007-10-31 Wed
2007-08-12 Sun の bison マニュアルの中間記法電卓
そのまま使用可能だった
4 + 4.5 - (34/(8*3+-3))
6.880952381
-56 + 2
-54
3 ^ 2
9
!2007-10-30 Tue
2007-08-11 Sat の bison マニュアルの逆ポーランド記法電卓
そのまま使用可能だった
実行結果
4 9 +
13
3 7 + 3 4 5 *+-
-13
3 7 + 3 4 5 * + - n
13
5 6 / 4 n +
-3.166666667
3 4 ^
81
以下の警告を消すにはどうしたら良いのだろうか?
警告: implicit declaration of function `yyparse'
!2007-10-29 Mon
「%nonassoc」
%{
#include
void yyerror(char *s);
int yylex(void);
%}
//%left '+'
%left '*'
%nonassoc '+'
%%
input:
| input line
;
line: '\n'
| expr '\n' { printf("\n"); }
;
expr: expr '+' expr { printf("|+|"); }
| expr '*' expr { printf("|*|"); }
| '(' expr ')'
| 'a' { printf("|a|"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
return yyparse();
}
で、
a*a
a*a*a
a+a
a+a+a
を入力すると、
|a||a||*|
|a||a||*||a||*|
|a||a||+|
|a||a|syntax error
!2007-10-28 Sun
2007-08-14 の bison マニュアルの多機能電卓に YYPRINT を追加
***************
*** 26,36 ****
--- 26,41 ----
#include /* cos(), sin()などの数学関数のため */
//#include "calc.h" /* `symrec'の定義を含む */
#include "20070814_bison00.h"
+
+ #define YYPRINT(file, type, value) yyprint (file, type, value)
%}
%union {
double val; /* 数値を返すため */
symrec *tptr; /* 記号表へのポインタを返すため */
}
+ %{
+ static void yyprint (FILE *file, int type, YYSTYPE value);
+ %}
%token NUM /* 単純な倍精度数値 */
%token VAR FNCT /* 変数と関数 */
***************
*** 73,80 ****
--- 78,99 ----
#include
+ static void
+ yyprint (file, type, value)
+ FILE *file;
+ int type;
+ YYSTYPE value;
+ {
+ if (type == VAR)
+ fprintf (file, " %s", value.tptr->name);
+ else if (type == NUM)
+ fprintf (file, " %d", value.val);
+ }
+
main ()
{
+ yydebug = 1;
+
init_table();
yyparse();
}
で、
pi = 3.141592653589
sin(pi)
alpha = beta1 = 2.3
alpha
ln(alpha)
exp(ln(beta1))
を入力すると、
Starting parse
Entering state 0
Reducing stack by rule 1 (line 54), -> input
Stack now 0
Entering state 1
Reading a token: Next token is token VAR ( pi)
Shifting token VAR, Entering state 5
Reading a token: Next token is token '=' ()
Shifting token '=', Entering state 13
Reading a token: Next token is token NUM ( 1413752350)
Shifting token NUM, Entering state 4
Reducing stack by rule 6 (line 64), NUM -> exp
Stack now 0 1 5 13
Entering state 23
Reading a token: Next token is token '\n' ()
Reducing stack by rule 8 (line 66), VAR '=' exp -> exp
Stack now 0 1
Entering state 11
Next token is token '\n' ()
Shifting token '\n', Entering state 22
Reducing stack by rule 4 (line 60), exp '\n' -> line
3.141592654
Stack now 0 1
Entering state 10
Reducing stack by rule 2 (line 55), input line -> input
Stack now 0
Entering state 1
Reading a token: Next token is token FNCT ()
Shifting token FNCT, Entering state 6
Reading a token: Next token is token '(' ()
Shifting token '(', Entering state 14
Reading a token: Next token is token VAR ( pi)
Shifting token VAR, Entering state 5
Reading a token: Next token is token ')' ()
Reducing stack by rule 7 (line 65), VAR -> exp
Stack now 0 1 6 14
Entering state 24
Next token is token ')' ()
Shifting token ')', Entering state 31
Reducing stack by rule 9 (line 67), FNCT '(' exp ')' -> exp
Stack now 0 1
Entering state 11
Reading a token: Next token is token '\n' ()
Shifting token '\n', Entering state 22
Reducing stack by rule 4 (line 60), exp '\n' -> line
7.932657894e-13
Stack now 0 1
Entering state 10
Reducing stack by rule 2 (line 55), input line -> input
Stack now 0
Entering state 1
Reading a token: Next token is token VAR ( alpha)
Shifting token VAR, Entering state 5
Reading a token: Next token is token '=' ()
Shifting token '=', Entering state 13
Reading a token: Next token is token VAR ( beta1)
Shifting token VAR, Entering state 5
Reading a token: Next token is token '=' ()
Shifting token '=', Entering state 13
Reading a token: Next token is token NUM ( 1717986918)
Shifting token NUM, Entering state 4
Reducing stack by rule 6 (line 64), NUM -> exp
Stack now 0 1 5 13 5 13
Entering state 23
Reading a token: Next token is token '\n' ()
Reducing stack by rule 8 (line 66), VAR '=' exp -> exp
Stack now 0 1 5 13
Entering state 23
Next token is token '\n' ()
Reducing stack by rule 8 (line 66), VAR '=' exp -> exp
Stack now 0 1
Entering state 11
Next token is token '\n' ()
Shifting token '\n', Entering state 22
Reducing stack by rule 4 (line 60), exp '\n' -> line
2.3
Stack now 0 1
Entering state 10
Reducing stack by rule 2 (line 55), input line -> input
Stack now 0
Entering state 1
Reading a token: Next token is token VAR ( alpha)
Shifting token VAR, Entering state 5
Reading a token: Next token is token '\n' ()
Reducing stack by rule 7 (line 65), VAR -> exp
Stack now 0 1
Entering state 11
Next token is token '\n' ()
Shifting token '\n', Entering state 22
Reducing stack by rule 4 (line 60), exp '\n' -> line
2.3
Stack now 0 1
Entering state 10
Reducing stack by rule 2 (line 55), input line -> input
Stack now 0
Entering state 1
Reading a token: Next token is token FNCT ()
Shifting token FNCT, Entering state 6
Reading a token: Next token is token '(' ()
Shifting token '(', Entering state 14
Reading a token: Next token is token VAR ( alpha)
Shifting token VAR, Entering state 5
Reading a token: Next token is token ')' ()
Reducing stack by rule 7 (line 65), VAR -> exp
Stack now 0 1 6 14
Entering state 24
Next token is token ')' ()
Shifting token ')', Entering state 31
Reducing stack by rule 9 (line 67), FNCT '(' exp ')' -> exp
Stack now 0 1
Entering state 11
Reading a token: Next token is token '\n' ()
Shifting token '\n', Entering state 22
Reducing stack by rule 4 (line 60), exp '\n' -> line
0.8329091229
Stack now 0 1
Entering state 10
Reducing stack by rule 2 (line 55), input line -> input
Stack now 0
Entering state 1
Reading a token: Next token is token FNCT ()
Shifting token FNCT, Entering state 6
Reading a token: Next token is token '(' ()
Shifting token '(', Entering state 14
Reading a token: Next token is token FNCT ()
Shifting token FNCT, Entering state 6
Reading a token: Next token is token '(' ()
Shifting token '(', Entering state 14
Reading a token: Next token is token VAR ( beta1)
Shifting token VAR, Entering state 5
Reading a token: Next token is token ')' ()
Reducing stack by rule 7 (line 65), VAR -> exp
Stack now 0 1 6 14 6 14
Entering state 24
Next token is token ')' ()
Shifting token ')', Entering state 31
Reducing stack by rule 9 (line 67), FNCT '(' exp ')' -> exp
Stack now 0 1 6 14
Entering state 24
Reading a token: Next token is token ')' ()
Shifting token ')', Entering state 31
Reducing stack by rule 9 (line 67), FNCT '(' exp ')' -> exp
Stack now 0 1
Entering state 11
Reading a token: Next token is token '\n' ()
Shifting token '\n', Entering state 22
Reducing stack by rule 4 (line 60), exp '\n' -> line
2.3
Stack now 0 1
Entering state 10
Reducing stack by rule 2 (line 55), input line -> input
Stack now 0
Entering state 1
Reading a token: Now at end of input.
* 「Reading a token: 」のところの括弧に内容が入っているという違いか?
* はじめて「%{ %}」を複数書いてみたか?
* 以前 YYSTYPE の定義と関数の宣言で問題が出てごまかしてしまったが、「%{ %}」を複数書くなど YYSTYPE 定義後に YYSTYPE を使用の関数宣言をすれば良いのか?
!2007-10-27 Sat
デバッグ
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input:
| input line
;
line : 'a' 'b' 'c' '\n' { printf("*abc*\n"); }
| 'd' 'e' 'f' '\n' { printf("*def*\n"); };
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yydebug = 1;
yyparse();
return 0;
}
で、コンパイル時「-DYYDEBUG=1」をつけて
abc
def
を入力すると、
./a.out < foo
Starting parse
Entering state 0
Reducing stack by rule 1 (line 17), -> input
Stack now 0
Entering state 1
Reading a token: Next token is token 'a' ()
Shifting token 'a', Entering state 3
Reading a token: Next token is token 'b' ()
Shifting token 'b', Entering state 6
Reading a token: Next token is token 'c' ()
Shifting token 'c', Entering state 8
Reading a token: Next token is token '\n' ()
Shifting token '\n', Entering state 10
Reducing stack by rule 3 (line 21), 'a' 'b' 'c' '\n' -> line
*abc*
Stack now 0 1
Entering state 5
Reducing stack by rule 2 (line 18), input line -> input
Stack now 0
Entering state 1
Reading a token: Next token is token 'd' ()
Shifting token 'd', Entering state 4
Reading a token: Next token is token 'e' ()
Shifting token 'e', Entering state 7
Reading a token: Next token is token 'f' ()
Shifting token 'f', Entering state 9
Reading a token: Next token is token '\n' ()
Shifting token '\n', Entering state 11
Reducing stack by rule 4 (line 22), 'd' 'e' 'f' '\n' -> line
*def*
Stack now 0 1
Entering state 5
Reducing stack by rule 2 (line 18), input line -> input
Stack now 0
Entering state 1
Reading a token: Now at end of input.
!2007-10-26 Fri
#define YYRECOVERING() (!!yyerrstatus)
という定義
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input:
| input line
;
line: '\n' { printf("*n*\n"); }
| expr '\n' { printf("*a*\n"); }
| error '\n' { printf("*%d*\n", YYRECOVERING());
printf("*a*\n"); yyerrok;
printf("*%d*\n", YYRECOVERING()); }
;
expr: 'a'
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
return yyparse();
}
で、
a
b
を入力すると、
*a*
syntax error
*1*
*a*
*0*
!2007-10-25 Thu
yyclearin 良く分かりません…。先読みが良く分かっていないので…
定義は「#define yyclearin (yychar = YYEMPTY)」
!2007-10-24 Wed
yyerrok
2007-10-23 Tue と
***************
*** 28,34 ****
expr: expr '+' expr { printf("|+|"); }
| expr '*' expr { printf("|*|"); }
| '(' expr ')'
! | '(' error ')' { printf("|error|\n"); }
| 'a' { printf("|a|"); }
;
--- 28,34 ----
expr: expr '+' expr { printf("|+|"); }
| expr '*' expr { printf("|*|"); }
| '(' expr ')'
! | '(' error ')' { printf("|error|\n"); yyerrok; }
| 'a' { printf("|a|"); }
;
という違い。
a
a+a
(a+a)+a
(aa)a+a
a
を入力すると、
|a|
|a||a||+|
|a||a||+||a||+|
|a|syntax error
|error|
syntax error
「#define yyerrok (yyerrstatus = 0)」
という定義のようなのだけど?何が変わるんだ?
!2007-10-23 Tue
error
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%left '+'
%left '*'
%%
input:
| input line
;
line: '\n'
| expr '\n' { printf("\n"); }
;
expr: expr '+' expr { printf("|+|"); }
| expr '*' expr { printf("|*|"); }
| '(' expr ')'
| '(' error ')' { printf("|error|\n"); }
| 'a' { printf("|a|"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
return yyparse();
}
で、
a
a+a
(a+a)+a
(aa)a+a
a
を入力すると、
|a|
|a||a||+|
|a||a||+||a||+|
|a|syntax error
|error|
?
a
a+a
(a+a)+a
(aa)
a+a
a
を入力すると、
|a|
|a||a||+|
|a||a||+||a||+|
|a|syntax error
|error|
|a||a||+|
|a|
!2007-10-22 Mon
2007-10-21 Sun で複数の error を書いてみる
***************
*** 20,26 ****
line: '\n' { printf("*n*\n"); }
| expr '\n' { printf("*a*\n"); }
! | error 'c' { printf("*error*\n"); }
;
expr: 'a'
--- 20,27 ----
line: '\n' { printf("*n*\n"); }
| expr '\n' { printf("*a*\n"); }
! | error 'c' { printf("*error*\n"); }
! | error 'd' { printf("*error*\n"); }
;
expr: 'a'
という違い。
a
bdca
を入力すると、
*a*
*n*
syntax error
*error*
*error*
*a*
!2007-10-21 Sun
error
2007-10-20 Sat で
***************
*** 20,26 ****
line: '\n' { printf("*n*\n"); }
| expr '\n' { printf("*a*\n"); }
! | error '\n' { printf("*error*\n"); }
;
expr: 'a'
--- 20,26 ----
line: '\n' { printf("*n*\n"); }
| expr '\n' { printf("*a*\n"); }
! | error 'c' { printf("*error*\n"); }
;
expr: 'a'
という違い。
a
bdca
を入力すると、
*a*
*n*
syntax error
*error*
*a*
!2007-10-20 Sat
error
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input:
| input line
;
line: '\n' { printf("*n*\n"); }
| expr '\n' { printf("*a*\n"); }
| error '\n' { printf("*error*\n"); }
;
expr: 'a'
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
return yyparse();
}
で、
a
b
a
を入力すると、
*a*
*n*
syntax error
*error*
*a*
!2007-10-19 Fri
YYMAXDEPTH, YYINITDEPTH 確認
#ifndef YYMAXDEPTH
# define YYMAXDEPTH 10000
#endif
#ifndef YYINITDEPTH
# define YYINITDEPTH 200
#endif
訳だと「YYINIDEPTH」になっているようだ
(アジソン・ウェスレイの本だと正しかった)
!2007-10-18 Thu
不可解な還元/還元衝突 解決編
2007-10-17 Wed で
***************
*** 29,36 ****
;
return_spec: type
! | name ':' type
;
type: 'a'
;
--- 29,37 ----
;
return_spec: type
! | 'a' ':' type
;
+
type: 'a'
;
という違い。
ワーニングなくなった
!2007-10-17 Wed
不可解な還元/還元衝突
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input:
| input line
;
line: def '\n'
;
def: param_spec return_spec ','
;
param_spec: type
| name_list ':' type
;
return_spec: type
| name ':' type
;
type: 'a'
;
name: 'a'
;
name_list:
name
| name ',' name_list
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
return yyparse();
}
で、
20071017_bison00.y: conflicts: 1 reduce/reduce
というワーニング
aa,
a:aa,
a:aa:a,
を入力すると、受理
!2007-10-16 Tue
還元/還元衝突
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input:
| input line
;
line: sequence '\n'
;
sequence : { printf("*empty sequence*\n"); }
| sequence words { printf("*sequence words*\n"); }
| sequence redirects { printf("*sequence redirects*\n"); }
;
words : { printf("*empty words*\n"); }
| words 'a' { printf("*words a*\n"); }
;
redirects :
| redirects 'b' { printf("*redirects b*\n"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
return yyparse();
}
で、
20071016_bison00.y: conflicts: 3 shift/reduce, 3 reduce/reduce
20071016_bison00.y:33.10: warning: rule never reduced because of conflicts: redirects: /* empty */
というワーニング
a
aa
aaa
b
bb
bbb
abab
を入力すると、
無限ループ???
還元/還元衝突の解消 その1
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input:
| input line
;
line: sequence '\n'
;
sequence : { printf("*empty sequence*\n"); }
| sequence 'a' { printf("*sequence words*\n"); }
| sequence 'b' { printf("*sequence redirects*\n"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
return yyparse();
}
で、
a
aa
aaa
b
bb
bbb
abab
を入力すると、
*empty sequence*
*sequence words*
*empty sequence*
*sequence words*
*sequence words*
*empty sequence*
*sequence words*
*sequence words*
*sequence words*
*empty sequence*
*sequence redirects*
*empty sequence*
*sequence redirects*
*sequence redirects*
*empty sequence*
*sequence redirects*
*sequence redirects*
*sequence redirects*
*empty sequence*
*sequence words*
*sequence redirects*
*sequence words*
*sequence redirects*
還元/還元衝突の解消 その2
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input:
| input line
;
line: sequence '\n'
;
sequence : { printf("*empty sequence*\n"); }
| sequence words { printf("*sequence words*\n"); }
| sequence redirects { printf("*sequence redirects*\n"); }
;
words : 'a' { printf("*a*\n"); }
| words 'a' { printf("*words a*\n"); }
;
redirects : 'b' { printf("*b*\n"); }
| redirects 'b' { printf("*redirects b*\n"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
return yyparse();
}
で、
20071016_bison02.y: conflicts: 2 shift/reduce
というワーニング
a
aa
aaa
b
bb
bbb
abab
を入力すると、
*empty sequence*
*a*
*sequence words*
*empty sequence*
*a*
*words a*
*sequence words*
*empty sequence*
*a*
*words a*
*words a*
*sequence words*
*empty sequence*
*b*
*sequence redirects*
*empty sequence*
*b*
*redirects b*
*sequence redirects*
*empty sequence*
*b*
*redirects b*
*redirects b*
*sequence redirects*
*empty sequence*
*a*
*sequence words*
*b*
*sequence redirects*
*a*
*sequence words*
*b*
*sequence redirects*
!2007-10-15 Mon
還元/還元衝突
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input:
| input line
;
line: '\n' { printf("\n"); }
| sequence '\n'
;
sequence : { printf("*empty input*\n"); }
| maybeword
| sequence 'a' { printf("*added word %c*\n", $2); }
;
maybeword : { printf("*empty maybeword*\n"); }
| 'a' { printf("*a*\n"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
return yyparse();
}
で、
20071015_bison00.y: conflicts: 2 shift/reduce, 2 reduce/reduce
20071015_bison00.y:25.28-57: warning: rule never reduced because of conflicts: sequence: /* empty */
20071015_bison00.y:30.29-62: warning: rule never reduced because of conflicts: maybeword: /* empty */
というワーニング
a
aa
aaa
を入力すると、
*a*
*a*
*added word a*
*a*
*added word a*
*added word a*
!2007-10-14 Sun
訳の話「UNIMISの優先順位を、規則の中で使えます」
「UNIMIS」でなくて「UMINUS」だよ〜。
ascii で配っていた info の時点で既に間違っているようだ
(アジソン・ウェスレイの本だと正しかった)
2007-10-11 Thu で
***************
*** 16,21 ****
--- 16,22 ----
%left '<' '>'
%left '+' '-'
%left '*' '/'
+ %left UMINUS
%%
***************
*** 34,39 ****
--- 35,41 ----
| expr '<' expr { printf("|< %d %d|", $1, $3); }
| expr '>' expr { printf("|> %d %d|", $1, $3); }
| '(' expr ')'
+ | '-' expr %prec UMINUS { printf("|- %d|", $2); }
| NUMBER { printf("|%d|", $1); }
;
という違い
1 - 2 * 3
1 - 2 - 5
1 + 2 - 5
-1 + 3
を入力すると、
|1||2||3||* 2 3||- 1 2|
|1||2||- 1 2||5||- 1 5|
|1||2||+ 1 2||5||- 1 5|
|1||- 1||3||+ 5 3|
!2007-10-13 Sat
2007-10-10 Wed で以下のように複数書いてみたら?
***************
*** 14,19 ****
--- 14,20 ----
%token NUMBER
%left '<'
+ %left '<'
%left '-'
%left '*'
20071013_bison00.y:17.1-5: redefining precedence of '<'
のエラー
!2007-10-12 Fri
2007-10-11 Thu で
***************
*** 13,19 ****
%}
%token NUMBER
! %left '<' '>'
%left '+' '-'
%left '*' '/'
--- 13,19 ----
%}
%token NUMBER
! %left '<' '>' "!=" "<=" ">="
%left '+' '-'
%left '*' '/'
という違い
文字列(リテラル文字列トークン)も問題なく書けるようだ
!2007-10-11 Thu
2007-10-09 Tue で
*** 13,18 ****
--- 13,21 ----
%}
%token NUMBER
+ %left '<' '>'
+ %left '+' '-'
+ %left '*' '/'
%%
***************
*** 24,32 ****
| expr '\n' { printf("\n"); }
;
! expr: expr '-' expr { printf("|- %d %d|", $1, $3); }
| expr '*' expr { printf("|* %d %d|", $1, $3); }
| expr '<' expr { printf("|< %d %d|", $1, $3); }
| '(' expr ')'
| NUMBER { printf("|%d|", $1); }
;
--- 27,38 ----
| expr '\n' { printf("\n"); }
;
! expr: expr '+' expr { printf("|+ %d %d|", $1, $3); }
! | expr '-' expr { printf("|- %d %d|", $1, $3); }
| expr '*' expr { printf("|* %d %d|", $1, $3); }
+ | expr '/' expr { printf("|/ %d %d|", $1, $3); }
| expr '<' expr { printf("|< %d %d|", $1, $3); }
+ | expr '>' expr { printf("|> %d %d|", $1, $3); }
| '(' expr ')'
| NUMBER { printf("|%d|", $1); }
;
という違い
1 - 2 * 3
1 - 2 - 5
1 + 2 - 5
を入力すると、
|1||2||3||* 2 3||- 1 2|
|1||2||- 1 2||5||- 1 5|
|1||2||+ 1 2||5||- 1 5|
!2007-10-10 Wed
2007-10-09 Tue で
***************
*** 13,18 ****
--- 13,21 ----
%}
%token NUMBER
+ %left '<'
+ %left '-'
+ %left '*'
%%
という違い
1 - 2 * 3
1 - 2 - 5
を入力すると、
|1||2||3||* 2 3||- 1 2|
|1||2||- 1 2||5||- 1 5|
!2007-10-09 Tue
演算子の優先順位
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%token NUMBER
%%
input:
| input line
;
line: '\n'
| expr '\n' { printf("\n"); }
;
expr: expr '-' expr { printf("|- %d %d|", $1, $3); }
| expr '*' expr { printf("|* %d %d|", $1, $3); }
| expr '<' expr { printf("|< %d %d|", $1, $3); }
| '(' expr ')'
| NUMBER { printf("|%d|", $1); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c;
while ((c = getchar()) == ' ')
;
if (c >= '0' && c <= '9') {
yylval = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
return yyparse();
}
で、
20071009_bison00.y: conflicts: 9 shift/reduce
というワーニング
1 - 2 * 3
1 - 2 - 5
を入力すると、
|1||2||3||* 2 3||- 1 2|
|1||2||5||- 2 5||- 1 2|
!2007-10-08 Mon
「%expect」
2007-10-07 Sun で、
***************
*** 13,18 ****
--- 13,19 ----
%}
%token NUMBER
+ %expect 1
%%
とすると、conflicts が表示されなくなる
「%expect 1」を「%expect 0」とすると、以下のワーニング
20071008_bison00.y: conflicts: 1 shift/reduce
20071008_bison00.y: warning: expected 0 shift/reduce conflicts
!2007-10-07 Sun
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%token NUMBER
%%
input:
| input line
;
line: '\n'
| stmt '\n'
stmt: expr
| if_stmt
;
if_stmt:
'I' expr 'T' stmt
| 'I' expr 'T' stmt 'E' stmt
;
expr: NUMBER
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
yylval = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
return yyparse();
}
で、
20071007_bison00.y: conflicts: 1 shift/reduce
の conflicts
I0T1
I0T1E2
I0TI1T2E3
I0T1EI2T3E4
を入力すると、エラーなしで受理
あっ、line のルールの最後で「;」が抜けているや
!2007-10-06 Sat
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input : 'a' { printf("%d %d", YYEMPTY, yychar); } '\n' { printf("*a*\n"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
return yyparse();
}
で、
a
を入力すると、
-2 -2*a*
先読みトークンがあるのかないのか良く分からない…
「#define YYEMPTY (-2)」なので、先読みトークンがないってことなのか?
!2007-10-05 Fri
YYBACKUP
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input : expr '\n'
;
expr : term '+' expr
| term
;
term : '(' expr ')' { YYBACKUP('1', '1'); }
| '1'
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
return yyparse();
}
で、
(1+1)
を入力すると、
syntax error: cannot back up
* どの時点でエラーになっているのか?
* ちゃんとした使い方になっていないと思う…
!2007-10-04 Thu
YYERROR_VERBOSE
%{
#include
void yyerror(char *s);
int yylex(void);
#define YYERROR_VERBOSE
%}
%%
input : 'a' '\n' { printf("*a*\n"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
int r = yyparse();
printf("yyparse: %d\n", r);
printf("yynerrs: %d\n", yynerrs);
return r;
}
で、
b
を入力すると、
syntax error, unexpected $undefined, expecting 'a'
yyparse: 1
yynerrs: 1
!2007-10-03 Wed
yyerror
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input : 'a' '\n' { printf("*a*\n"); }
;
%%
#if 0
void yyerror(char *s)
{
printf("%s\n", s);
}
#endif
int yylex(void)
{
return getchar();
}
int main()
{
int r = yyparse();
printf("yyparse: %d\n", r);
return r;
}
で、
b
を入力すると、
syntax error
yyparse: 1
* -ly つきでコンパイルしないとエラー
* 昔は "parse error" という文字列だったのか〜
!2007-10-02 Tue
YYERROR
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input : 'a' { printf("*a*\n"); }
'\n' { printf("**a**\n"); }
| 'b' { printf("*b*\n"); YYERROR; }
'\n' { printf("**b**\n"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
int r = yyparse();
printf("yyparse: %d\n", r);
return r;
}
で、
a
を入力すると、
*a*
**a**
yyparse: 0
b
を入力すると、
*b*
yyparse: 1
!2007-10-01 Mon
再入可能構文解析器
%{
#include
void yyerror(char *s);
int yylex (int *lvalp, void *parm);
//int yylex (YYSTYPE *lvalp);
struct parser_control
{
int nastiness;
int randomness;
};
#define YYPARSE_PARAM parm
#define YYLEX_PARAM parm
%}
%pure_parser
%token NUMBER
%%
input :
| input line
;
line : '\n'
| expr '\n' { printf("%d\n", $1);
printf("%d %d\n",
((struct parser_control *) parm)->nastiness,
((struct parser_control *) parm)->randomness); }
;
expr : NUMBER { $$ = $1; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(YYSTYPE *lvalp, void *parm)
{
int c = getchar();
if (c >= '0' && c <= '9') {
*lvalp = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
struct parser_control foo;
foo.nastiness = 1;
foo.randomness = 10;
return yyparse((void *) &foo);
}
使い方不明。flex とかで使える???
!2007-09-30 Sun
再入可能構文解析器
%{
#include
void yyerror(char *s);
int yylex (int *lvalp);
//int yylex (YYSTYPE *lvalp);
struct parser_control
{
int nastiness;
int randomness;
};
#define YYPARSE_PARAM parm
%}
%pure_parser
%token NUMBER
%%
input :
| input line
;
line : '\n'
| expr '\n' { printf("%d\n", $1);
printf("%d %d\n",
((struct parser_control *) parm)->nastiness,
((struct parser_control *) parm)->randomness); }
;
expr : NUMBER { $$ = $1; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(YYSTYPE *lvalp)
{
int c = getchar();
if (c >= '0' && c <= '9') {
*lvalp = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
struct parser_control foo;
foo.nastiness = 1;
foo.randomness = 10;
return yyparse((void *) &foo);
}
で、
1
を入力すると、
1
1 10
!2007-09-29 Sat
再入可能構文解析器
%{
#include
void yyerror(char *s);
//int yylex (YYSTYPE *lvalp, YYLTYPE *llocp);
%}
%pure_parser
%token NUMBER
%%
input :
| input line
;
line : expr { printf("@1.first_line: %d\n", @1.first_line);
printf("@1.last_line: %d\n", @1.last_line);
printf("@1.first_column: %d\n", @1.first_column);
printf("@1.last_column: %d\n", @1.last_column); }
'\n' { printf("@3.first_line: %d\n", @3.first_line);
printf("@3.last_line: %d\n", @3.last_line);
printf("@3.first_column: %d\n", @3.first_column);
printf("@3.last_column: %d\n", @3.last_column); }
;
expr : NUMBER { $$ = $1; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(YYSTYPE *lvalp, YYLTYPE *llocp)
{
int c = getchar();
llocp->first_line++;
llocp->last_line++;
llocp->first_column++;
llocp->last_column++;
if (c >= '0' && c <= '9') {
*lvalp = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
return yyparse();
}
で、
1
を入力すると、
@1.first_line: 134516209
@1.last_line: -1073743207
@1.first_column: 134521377
@1.last_column: 134513342
@3.first_line: 134516210
@3.last_line: -1073743206
@3.first_column: 134521378
@3.last_column: 134513343
どこでどうやって初期化すれば?
!2007-09-28 Fri
再入可能構文解析器
%{
#include
void yyerror(char *s);
int yylex (int *lvalp);
//int yylex (YYSTYPE *lvalp);
%}
%pure_parser
%token NUMBER
%%
input :
| input line
;
line : '\n'
| expr '\n' { printf("%d\n", $1); }
;
expr : NUMBER { $$ = $1; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(YYSTYPE *lvalp)
{
int c = getchar();
if (c >= '0' && c <= '9') {
*lvalp = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
return yyparse();
}
で、
1
を入力すると、
1
* 関数プロトタイプで YYSTYPE を使うには?
!2007-09-27 Thu
%{
#include
%}
%%
input :
| input line
;
line : 'a' { printf("@1.first_line: %d\n", @1.first_line);
printf("@1.last_line: %d\n", @1.last_line);
printf("@1.first_column: %d\n", @1.first_column);
printf("@1.last_column: %d\n", @1.last_column); }
'\n' { printf("@3.first_line: %d\n", @3.first_line);
printf("@3.last_line: %d\n", @3.last_line);
printf("@3.first_column: %d\n", @3.first_column);
printf("@3.last_column: %d\n", @3.last_column); }
;
%%
yyerror(char *s)
{
printf("%s\n", s);
}
yylex()
{
int c = getchar();
yylloc.first_line++;
yylloc.last_line++;
yylloc.first_column++;
yylloc.last_column++;
return c;
}
main()
{
yyparse();
}
で、
a
を入力すると、
@1.first_line: 1
@1.last_line: 1
@1.first_column: 1
@1.last_column: 1
@3.first_line: 2
@3.last_line: 2
@3.first_column: 2
@3.last_column: 2
yylex がダメなので、値は不適切
!2007-09-26 Wed
文字列リテラル
%{
#include
%}
%token EQ "=="
%token NE "!="
%token LE "<="
%token GE ">="
%%
input : 'a' EQ 'a' '\n' { printf("*a == a*\n"); }
;
%%
yyerror(char *s)
{
printf("%s\n", s);
}
yylex()
{
int c = getchar();
if (c == '=') {
c = getchar();
if (c == '=') {
return EQ;
} else {
ungetc(c, stdin); return c;
}
} else if (c == '!') {
if (c == '=') {
return NE;
} else {
ungetc(c, stdin); return c;
}
} else if (c == '<') {
if (c == '=') {
return LE;
} else {
ungetc(c, stdin); return c;
}
} else if (c == '>') {
if (c == '=') {
return GE;
} else {
ungetc(c, stdin); return c;
}
} else {
return c;
}
}
main()
{
yyparse();
}
で、
a==a
を入力すると、
*a == a*
!2007-09-25 Tue
YYACCEPT, YYABORT
%{
#include
%}
%%
input : 'a' { printf("*a*\n"); YYACCEPT; }
'\n' { printf("**a**\n"); }
| 'b' { printf("*b*\n"); YYABORT; }
'\n' { printf("**b**\n"); }
;
%%
yyerror(char *s)
{
printf("%s\n", s);
}
yylex()
{
return getchar();
}
main()
{
printf("yyparse: %d\n", yyparse());
}
で、
a
を入力すると、
*a*
yyparse: 0
b
を入力すると、
*b*
yyparse: 1
!2007-09-24 Mon
yyparse() の戻り値
%{
#include
%}
%%
input : 'a' '\n' { printf("*a*\n"); };
%%
yyerror(char *s)
{
printf("%s\n", s);
}
yylex()
{
return getchar();
}
main()
{
printf("yyparse: %d\n", yyparse());
}
で、
a
を入力すると、
*a*
yyparse: 0
a
b
を入力すると、
*a*
syntax error
yyparse: 1
!2007-09-23 Sun
オプション`-p prefix'
%{
#include
%}
%%
input : 'a' '\n' { printf("*a*\n"); };
%%
cerror(char *s)
{
printf("%s\n", s);
}
clex()
{
return getchar();
}
main()
{
cparse();
}
で、-p c つきで実行
a
を入力すると、
*a*
!2007-09-22 Sat
「%token_table」
* あまり良く分からない…
* %token_table なくても yytname[] はある気が?
!2007-09-21 Fri
「%raw」
あるの???
!2007-09-20 Thu
「%no_lines」
「#line」以外のところも変わっているような気もするが?
!2007-09-19 Wed
「%expect」とばし
「%start」
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%start input
%%
line : 'a' 'b' 'c' '\n' { printf("*abc*\n"); }
;
input :
| input line
;
%%
void yyerror(char *s)
{
printf ("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
!2007-09-18 Tue
2007-09-14 で
***************
*** 23,30 ****
%}
! %token NUMBER
! %type NUMBER
%%
--- 23,29 ----
%}
! %token NUMBER
%%
と %token に型を書くことも可能
!2007-09-17 Mon
%{
#include
void yyerror(char *s);
int yylex(void);
int x = 99;
%}
%%
input : subroutine '0' '1' '\n' { printf("x: %d $3: %d\n", x, $3); }
| subroutine '0' '\n' { printf("x: %d $2: %d\n", x, $2); }
;
subroutine : { printf("x: %d\n", x); x = 0; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
yyparse();
return 0;
}
で、
0
を入力すると、
x: 99
x: 0 $2: 48
01
を入力すると、
x: 99
x: 0 $3: 49
!2007-09-16 Sun
%{
#include
void yyerror(char *s);
int yylex(void);
int x = 99;
%}
%%
input : { printf("x: %d\n", x); x = 0; } later
;
later : '0' '1' '\n' { printf("x: %d $2: %d\n", x, $2); }
| '0' '\n' { printf("x: %d $1: %d\n", x, $1); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
yyparse();
return 0;
}
で、
0
を入力すると、
x: 99
x: 0 $1: 48
01
を入力すると、
x: 99
x: 0 $2: 49
!2007-09-15 Sat
%{
#include
void yyerror(char *s);
int yylex(void);
int x = 99;
%}
%%
input : { printf("x: %d\n", x); x = 0; }
'0' '1' '\n' { printf("x: %d $3: %d\n", x, $2); }
| '0' '\n' { printf("x: %d $1: %d\n", x, $1); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
yyparse();
return 0;
}
で、
20070915_bison00.y: conflicts: 1 shift/reduce
20070915_bison00.y:19.22-53: warning: rule never reduced because of conflicts: @1: /* empty */
のワーニング
01
を入力すると、
syntax error
0
を入力すると、
x: 99 $1: 48
!2007-09-14 Fri
YYSTYPE
%{
#include
void yyerror(char *s);
int yylex(void);
typedef struct {
enum {INT, DBL} type;
union {
int i;
double d;
} val;
} yystype;
#define YYSTYPE yystype
%}
%token NUMBER
%type NUMBER
%%
input :
| input line
;
line : exp '\n' { if ($1 == INT)
printf("%d\n", $1);
else
printf("%f\n", $1); }
;
exp : NUMBER { $$ = INT; $$ = $1; }
| NUMBER '.' NUMBER { $$ = DBL;
$$ = $1; $$ += $3 / 10.0; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
yylval.val.i = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
1
1.2
を入力すると、
1
1.200000
!2007-09-13 Thu
規則の途中のアクション
%{
#include
void yyerror(char *s);
int yylex(void);
int x = 99;
%}
%token ALPHA NUMBER
%%
input : '0' { printf("x: %d $1: %d\n", x, $1); x = 0; }
'1' { printf("x: %d $3: %d\n", x, $3); x = 1; }
'\n' { printf("x: %d *%d %d*\n", x, $1, $3); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
yyparse();
return 0;
}
で、
01
を入力すると、
x: 99 $1: 48
x: 0 $3: 49
x: 1 *48 49*
!2007-09-12 Wed
「%union」の中に二重に情報を持つのが変に思ったので、まとめてみる
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%union{
struct {
enum {INT, DBL} type;
union {
int i;
double d;
} u;
} val;
}
%token NUMBER
%type NUMBER
%%
input :
| input line
;
line : exp '\n' { if ($1 == INT)
printf("%d\n", $1);
else
printf("%f\n", $1); }
;
exp : NUMBER { $$ = INT; $$ = $1; }
| NUMBER '.' NUMBER { $$ = DBL;
$$ = $1; $$ += $3 / 10.0; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
yylval.val.u.i = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
1
1.2
を入力すると、
1
1.200000
はじめ、struct を書かずに int, double, type が共有されてしまい、
おかしな動きになってしまった…
!2007-09-11 Tue
2007-09-04 ので %type を未使用に
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%union {
int ival;
double dval;
}
%token NUMBER
//%type NUMBER
//%type expr
%%
input :
| input line
;
line : '\n'
| expr '\n' { printf("%f\n", $1); }
;
expr : NUMBER { $$ = $1; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
yylval.ival = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
1
を入力すると、
1.000000
.tab.c は、
switch (yyn)
{
case 5:
#line 31 "20070911_bison00.y"
{ printf("%f\n", yyvsp[-1].dval); ;}
break;
case 6:
#line 34 "20070911_bison00.y"
{ yyval.dval = yyvsp[0].ival; ;}
break;
}
!2007-09-10 Mon
「$0」
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input : '0' foo '1' '\n' { printf("*%d %d*\n", $1, $3); }
;
foo : /* empty */ { printf("**%d**\n", $0); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
yyparse();
return 0;
}
で、
01
を入力すると、
**48**
*48 49*
!2007-09-09 Sun
「%union」
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%union{
int ival;
struct {
enum {INT, DBL} type;
union {
int i;
double d;
} u;
} val;
}
%token NUMBER
%type exp
%type NUMBER
%%
input :
| input line
;
line : exp '\n' { if ($1.type == INT)
printf("%d\n", $1.u.i);
else
printf("%f\n", $1.u.d); }
;
exp : NUMBER { $$.type = INT; $$.u.i = $1; }
| NUMBER '.' NUMBER { $$.type = DBL; $$.u.d = $1; $$.u.d += $3 / 10.0 }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
yylval.ival = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
1
1.2
を入力すると、
1
1.200000
どうもトリッキーだよな〜
!2007-09-08 Sat
アクションと $n
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%token NUMBER
%%
input :
| input line
;
line : NUMBER '\n' { printf("*%d*\n", $1); }
| NUMBER '.' NUMBER '\n' { printf("*%d.%d*\n", $1, $3); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
yylval = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
1
1.2
を入力すると、
*1*
*1.2*
間違えて、「printf("*%d.%d*\n", $1, $3);」を「printf("*%d.%d*\n", $1, $2);」
としたら、
*1*
*1.1*
となった
!2007-09-07 Fri
アクションと $n
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%token ALPHA NUMBER
%%
input : '0' '1' '\n' { printf("*%d %d*\n", $1, $2); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return (yylval = getchar());
}
int main()
{
yyparse();
return 0;
}
で、
01
を入力すると、
*48 49*
!2007-09-06 Thu
アクションと $n
%{
#include
void yyerror(char *s);
int yylex(void);
%}
//%token NUMBER
%%
input : '1' '\n' { printf("*%d*\n", $1); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
1
を入力すると、
*0*
あれ?そんなもん?と思ったが、
***************
*** 28,34 ****
int yylex(void)
{
! return getchar();
}
int main()
--- 28,34 ----
int yylex(void)
{
! return (yylval = getchar());
}
int main()
と変更したら、
*49*
の出力
!2007-09-05 Wed
アクションと $n
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%token NUMBER
%%
input : NUMBER '\n' { printf("*%d*\n", $1); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
yylval = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
1
を入力すると、
*1*
!2007-09-04 Tue
単純なものを試す
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%union {
int ival;
double dval;
}
%token NUMBER
%type NUMBER
%type expr
%%
input :
| input line
;
line : '\n'
| expr '\n' { printf("%f\n", $1); }
;
expr : NUMBER { $$ = $1; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
yylval.ival = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
1
2
を入力すると、
1.000000
2.000000
生成された C を見てみると、
case 5:
#line 32 "20070904_bison00.y"
{ printf("%f\n", yyvsp[-1].dval); ;}
break;
case 6:
#line 35 "20070904_bison00.y"
{ yyval.dval = yyvsp[0].ival; ;}
break;
なるへそ
!2007-09-03 Mon
単純なものを試す
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%union {
int val;
}
%token NUMBER
%type expr NUMBER
//%type NUMBER
//%type expr
%%
input :
| input line
;
line : '\n'
| expr '\n'
;
expr : NUMBER { $$ = $1; }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
yylval.val = c - '0';
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
1
2
を入力すると、エラーなく受理
!2007-09-02 Sun
単純なものを試す
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%union {
int val;
}
%token NUMBER
%type expr
%%
input :
| input line
;
line : '\n'
| expr '\n'
;
expr : NUMBER
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
20070902_bison00.y:32.9-14: warning: type clash on default action: != <>
というワーニング
で、
1
2
を入力すると、エラーなく受理
!2007-09-01 Sat
単純なものを試す
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%token NUMBER
%%
input :
| input line
;
line : '\n'
| expr '\n'
;
expr : NUMBER
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c >= '0' && c <= '9') {
return NUMBER;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
1
2
を入力すると、エラーなく受理
!2007-08-31 Fri
相互再帰
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input :
| input line
;
line : '\n'
| expr '\n'
;
expr : primary
| primary '+' primary
;
primary: 'a'
| '(' expr ')'
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
a
(a)
a+a
(a+a)
(a+a)+a
を入力すると、エラーなく受理
!2007-08-30 Thu
単純なものを試す
右再帰
昨日のとの差分
***************
*** 26,32 ****
;
expseq1: 'a'
! | expseq1 ',' 'a'
;
%%
--- 27,33 ----
;
expseq1: 'a'
! | 'a' ',' expseq1
;
%%
!2007-08-29 Wed
単純なものを試す
カンマで区切られた0個以上のグループ
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input :
| input line
;
line : expseq '\n'
;
expseq: /* empty */
| expseq1
;
expseq1: 'a'
| expseq1 ',' 'a'
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
a
a,a
a,a,a
を入力すると、エラーなく受理
「空」は翻訳してはダメな気が。英語だと「empty」だった
!2007-08-28 Tue
単純なものを試す。yylex で 0 を返すとき
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input :
| 'a' 'b' '\n' { printf("*ab*\n"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
if (c == 'e') {
return 0;
} else {
return c;
}
}
int main()
{
yyparse();
return 0;
}
で、
e
を入力すると、エラーなし
!2007-08-27 Mon
単純なものを試す。%token
%{
#include
void yyerror(char *s);
int yylex(void);
#define TOKEN_A 258
#define TOKEN_B 259
#define TOKEN_NL 260
%}
%token TOKEN_A TOKEN_B TOKEN_NL
%%
input : TOKEN_A TOKEN_B TOKEN_NL { printf("*ab*\n"); }
;
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
int c = getchar();
yylval = c;
if (c == 'a') {
return TOKEN_A;
} else if (c == 'b') {
return TOKEN_B;
} else if (c == '\n') {
return TOKEN_NL;
} else {
}
}
int main()
{
yyparse();
return 0;
}
で、
ab
を入力すると、
*ab*
* 「%token」の意味がやっと分かったよ…
* 「#define TOKEN_*」は不要だった。というか、本来あっちゃダメ
!2007-08-26 Sun
単純なものを試す
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input : 'a'
| input 'b' 'a' { printf("*aba*\n"); }
;
%%
void yyerror(char *s)
{
printf ("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
abababa
(本当は改行なし)を入力すると、
*aba*
*aba*
*aba*
!2007-08-25 Sat
単純なものを試す。0回以上の繰り返し
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input :
| input 'a' { printf("*a*\n"); }
;
%%
void yyerror(char *s)
{
printf ("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
aaaa
(本当は改行なし)を入力すると、
*a*
*a*
*a*
*a*
!2007-08-24 Fri
単純なものを試す。一回以上の繰り返し
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input : 'a'
| input 'a' { printf("*a*\n"); }
;
%%
void yyerror(char *s)
{
printf ("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
aaaa
(本当は改行なし)を入力すると、
*a*
*a*
*a*
!2007-08-23 Thu
単純なものを試す。任意、何もないか一つあり
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input :
| 'a' { printf("*a*\n"); }
;
%%
void yyerror(char *s)
{
printf ("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
a
(本当は改行なし)を入力すると、
*a*
入力なしでも未エラー
!2007-08-22 Wed
単純なものを試す。改行のみの行も許す
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input :
| input line
;
line : '\n'
| 'a' 'b' 'c' '\n' { printf("*abc*\n"); }
;
%%
void yyerror(char *s)
{
printf ("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
abc
abc
を入力すると、
*abc*
*abc*
!2007-08-21 Tue
単純なものを試す。複数行の入力対応
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input :
| input line
;
line : 'a' 'b' 'c' '\n' { printf("*abc*\n"); }
;
%%
void yyerror(char *s)
{
printf ("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
abc
abc
を入力すると、
*abc*
*abc*
input : input line
;
だと、
20070821_bison01.y: warning: 3 useless nonterminals and 3 useless rules
20070821_bison01.y:16.1-5: fatal error: start symbol input does not derive any sentence
のエラー
なるへそ
!2007-08-20 Mon
単純なものを試す。選択
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input: 'a' 'b' 'c' '\n' { printf("*abc*\n"); }
| 'd' 'e' 'f' '\n' { printf("*def*\n"); };
%%
void yyerror(char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
で、
abc
def
を入力すると、
*abc*
syntax error
def
を入力すると、
*def*
!2007-08-19 Sun
単純なものを試す
昨日のソースだと -Wall -W でワーニングたくさん。
直したつもり
%{
#include
void yyerror(char *s);
int yylex(void);
%}
%%
input: 'a' '\n' { printf("*a*\n"); };
%%
void yyerror (char *s)
{
printf("%s\n", s);
}
int yylex(void)
{
return getchar();
}
int main()
{
yyparse();
return 0;
}
!2007-08-18 Sat
単純なものを試す。連続
%{
#include
%}
%%
input: 'a' '\n' { printf("*a*\n"); };
%%
yyerror(char *s)
{
printf("%s\n", s);
}
yylex()
{
return getchar();
}
main()
{
yyparse();
}
で、
a
を入力すると、
*a*
!2007-08-17 Fri
練習問題
初期化されていない変数について、値を書き込むのではなく、
値を使おうとするとエラーを報告するように、プログラムを改良しなさい。
現状だと、
x
0
x + 1
1
という動作。
***************
*** 194,203 ****
--- 200,218 ----
symbuf[i] = '\0';
s = getsym (symbuf);
+ #if 0
if (s == 0)
s = putsym (symbuf, VAR);
yylval.tptr = s;
return s->type;
+ #else
+ if (s == 0) {
+ fprintf(stderr, "Unkown variable %s\n", symbuf);
+ } else {
+ yylval.tptr = s;
+ return s->type;
+ }
+ #endif
}
/* その他の文字は文字リテラルトークン */
で、
x
Unkown variable x
x + 1
Unkown variable x
syntax error
* 読み飛ばしているだけなので、なんかいまいちな気もするが…
* 「syntax error」が出るのは変だな。あれれ? lex で正しい値を返していないからか?
* まずかったか?最初の代入で「Unkown variable」が表示されちゃう?でも lex で操作しているからしょうがないか??? (2007-11-05 Mon)
* 作り直してみたが、シンボル名の管理をどうやれば良いか分からなかったので、値は書き込んでしまって、(本当の)値が書き込まれたかの管理をすることにした。
!2007-08-16 Thu
練習問題
定数の名前と値を記憶する別の配列を追加しなさい
***************
*** 102,107 ****
--- 103,120 ----
0, 0
};
+ struct const_t
+ {
+ char *cname;
+ double val;
+ };
+
+ struct const_t const_tbl[] = {
+ "PI", 3.14159265358979,
+ "E", 2.71828182845905,
+ 0, 0,
+ };
+
/* 記号表:`struct symrec'のリスト */
symrec *sym_table = (symrec *)0;
***************
*** 114,119 ****
--- 127,137 ----
ptr = putsym(arith_fncts[i].fname, FNCT);
ptr->value.fnctptr = arith_fncts[i].fnct;
}
+ for (i = 0; const_tbl[i].cname != 0; i++)
+ {
+ ptr = putsym(const_tbl[i].cname, VAR);
+ ptr->value.var = const_tbl[i].val;
+ }
}
symrec *
で、
PI
3.141592654
PI * 2
6.283185307
E
2.718281828
ln(E)
1
!2007-08-15 Wed
練習問題
`math.h'にある関数のいくつかを、初期化リストに追加しなさい
***************
*** 99,104 ****
--- 99,105 ----
"ln", log,
"exp", exp,
"sqrt", sqrt,
+ "ceil", ceil,
0, 0
};
で、
ceil(1.2)
2
ceil(-1.2)
-1
二引数以上のを入れないと練習にならないか〜
!2007-08-14 Tue
bison マニュアルの多機能電卓
pi = 3.141592653589
3.141592654
sin(pi)
7.932657894e-13
alpha = beta1 = 2.3
2.3
alpha
2.3
ln(alpha)
0.8329091229
exp(ln(beta1))
2.3
!2007-08-13 Mon
bison マニュアルの中間記法電卓
エラー処理入り
昨日のエラー処理なしだと、
a
syntax error
エラーで、終了
エラー処理ありだと、
a
syntax error
1+2
3
!2007-08-12 Sun
bison マニュアルの中間記法電卓
4 + 4.5 - (34/(8*3+-3))
6.880952381
-56 + 2
-54
3 ^ 2
9
!2007-08-11 Sat
bison マニュアルの逆ポーランド記法電卓
4 9 +
13
3 7 + 3 4 5 *+-
-13
3 7 + 3 4 5 * + - n
13
5 6 / 4 n +
-3.166666667
3 4 ^
81
!2007-08-10 Fri
flex/examples/manual/expr.lex
cup で
import java_cup.runtime.*;
%%
%{
private Symbol symbol(int type) {
return new Symbol(type, yyline, yycolumn);
}
private Symbol symbol(int type, Object value) {
return new Symbol(type, yyline, yycolumn, value);
}
%}
%class Lexer
%unicode
%line
%column
%cup
%%
[0-9]+ { return symbol(sym.NUMBER, new Double(yytext())); }
[0-9]+\.[0-9]+ { return symbol(sym.NUMBER, new Double(yytext())); }
"+" { return symbol(sym.PLUS); }
"-" { return symbol(sym.MINUS); }
"*" { return symbol(sym.MULT); }
"/" { return symbol(sym.DIV); }
"^" { return symbol(sym.EXPON); }
"(" { return symbol(sym.LB); }
")" { return symbol(sym.RB); }
\n { return symbol(sym.EOL); }
[\t ]* { }
. { System.err.println("Illegal input");
return symbol(sym.EOL); }
cup ファイル
import java_cup.runtime.*;
terminal PLUS, MINUS, MULT, DIV, EXPON, EOL, LB, RB;
terminal Double NUMBER;
non terminal Object input, line;
non terminal Double exp;
precedence left MINUS, PLUS;
precedence left MULT, DIV;
precedence right EXPON;
input ::=
| input line
;
line ::= EOL
| exp:e EOL {: System.out.println(e); :}
;
exp ::= NUMBER:n {: RESULT = n; :}
| exp:e1 PLUS exp:e2 {: RESULT = new Double(e1.doubleValue() + e2.doubleValue()); :}
| exp:e1 MINUS exp:e2 {: RESULT = new Double(e1.doubleValue() - e2.doubleValue()); :}
| exp:e1 MULT exp:e2 {: RESULT = new Double(e1.doubleValue() * e2.doubleValue()); :}
| exp:e1 DIV exp:e2 {: RESULT = new Double(e1.doubleValue() / e2.doubleValue()); :}
| exp:e1 EXPON exp:e2 {: RESULT = new Double(Math.pow(e1.doubleValue(), e2.doubleValue())); :}
| LB exp:e RB {: RESULT = e; :}
;
Main.java (jflex-1.4.1/examples/cup/Main.java 改)
import java.io.*;
class Main {
static public void main(String argv[]) {
parser p;
try {
if (argv.length > 0) {
p = new parser(new Lexer(new FileReader(argv[0])));
} else {
p = new parser(new Lexer(new InputStreamReader(System.in)));
}
Object result = p.parse().value;
} catch (Exception e) {
e.printStackTrace();
}
}
}
で、
1+2*3
7.0
2^3+4
12.0
(1+2)*4
12.0
* なぜか改行を余計に打たないと値が出力されない…
* 「MINUS exp %prec MINUS」未実装。「| MINUS exp:e {: RESULT = new Double(-e.doubleValue()); :} %prec MINUS」を追加すれば良いようだ
!2007-08-09 Thu
flex/examples/manual/expr.lex
とりあえず、kmyacc で
* うーん、すごい苦労してしまった。分かってなさ過ぎ…
* kmyacc のサンプルの Calc.jy と jflex の byaccj/calc.{flex,y} あたりも参考に
* Java の参照の仕方さっぱり分かっておらず、、、
* yylval 経由で値を受け渡すという間抜けなことをやっているのもダメなところ
* expr.y 一部移植し損ねているじゃないか〜
%%
%{
private Calc yyparser;
public Object yylval;
public Lexer(java.io.Reader r, Calc yyparser) {
this(r);
this.yyparser = yyparser;
}
%}
%class Lexer
%unicode
%line
%column
%byaccj
%%
[0-9]+ { yylval = new Double(yytext()); return yyparser.NUMBER; }
[0-9]+\.[0-9]+ { yylval = new Double(yytext()); return yyparser.NUMBER; }
"+" { return(yyparser.PLUS); }
"-" { return(yyparser.MINUS); }
"*" { return(yyparser.MULT); }
"/" { return(yyparser.DIV); }
"^" { return(yyparser.EXPON); }
"(" { return(yyparser.LB); }
")" { return(yyparser.RB); }
\n { return(yyparser.EOL); }
[\t ]* { }
. { System.err.println("Illegal input");
return(yyparser.EOL); }
Calc.jy は、
%{
import java.io.*;
%}
%token NUMBER
%token PLUS MINUS MULT DIV EXPON
%token EOL
%token LB RB
%type expr NUMBER
%left MINUS PLUS
%left MULT DIV
%right EXPON
%%
start: lines;
lines: /* empty */
| lines line { yylrec++; }
;
line: expr EOL { System.out.println($1); }
| EOL { System.out.println("(empty line ignored)"); }
| error EOL
;
expr: expr PLUS expr { $$ = new Double($1.doubleValue() + $3.doubleValue()); }
| expr MINUS expr { $$ = new Double($1.doubleValue() - $3.doubleValue()); }
| expr MULT expr { $$ = new Double($1.doubleValue() * $3.doubleValue()); }
| expr DIV expr { $$ = new Double($1.doubleValue() / $3.doubleValue()); }
| LB expr RB { $$ = $2; }
| NUMBER { $$ = $1; }
;
%%
private Lexer lexer;
int yylex() {
int r = -1;
try {
r = lexer.yylex();
yylval = lexer.yylval;
} catch (IOException e) {
System.err.println("IO error :"+e);
}
return r;
}
void yyerror(String msg) {
System.err.println(msg);
}
public Calc() {
lexer = new Lexer(new InputStreamReader(System.in), this);
}
public static void main(String args[]) {
yydebug = true;
// yyDumpParseTree = true;
Calc it = new Calc();
it.yyparse();
}
で、
1+2+3
6.0
4+5*6-3
31.0
1.2+3.4
4.6
!2007-08-08 Wed
flex/examples/manual/pascal.lex
%%
%{
private int line_number = 0;
%}
%class Lexer
%unicode
%line
%column
%standalone
%x COMMENT1 COMMENT2
white_space = [ \t]*
digit = [0-9]
alpha = [A-Za-z_]
alpha_num = ({alpha}|{digit})
hex_digit = [0-9A-F]
identifier = {alpha}{alpha_num}*
unsigned_integer = {digit}+
hex_integer = ${hex_digit}{hex_digit}*
exponent = e[+-]?{digit}+
i = {unsigned_integer}
real = ({i}\.{i}?|{i}?\.{i}){exponent}?
string = \'([^'\n]|\'\')+\'
bad_string = \'([^'\n]|\'\')+
%%
"{" { yybegin(COMMENT1); }
[^}\n]+ { }
\n { ++line_number; }
<> { System.err.println("EOF in comment"); }
"}" { yybegin(YYINITIAL); }
"(*" { yybegin(COMMENT2); }
[^)*\n]+ { }
\n { ++line_number; }
<> { System.err.println("EOF in comment"); }
"*)" { yybegin(YYINITIAL); }
[*)] { }
and { return(AND); }
array { return(ARRAY); }
begin { return(_BEGIN); }
case { return(CASE); }
const { return(CONST); }
div { return(DIV); }
do { return(DO); }
downto { return(DOWNTO); }
else { return(ELSE); }
end { return(END); }
file { return(_FILE); }
for { return(FOR); }
function { return(FUNCTION); }
goto { return(GOTO); }
if { return(IF); }
in { return(IN); }
label { return(LABEL); }
mod { return(MOD); }
nil { return(NIL); }
not { return(NOT); }
of { return(OF); }
packed { return(PACKED); }
procedure { return(PROCEDURE); }
program { return(PROGRAM); }
record { return(RECORD); }
repeat { return(REPEAT); }
set { return(SET); }
then { return(THEN); }
to { return(TO); }
type { return(TYPE); }
until { return(UNTIL); }
var { return(VAR); }
while { return(WHILE); }
with { return(WITH); }
"<="|"=<" { return(LEQ); }
"=>"|">=" { return(GEQ); }
"<>" { return(NEQ); }
"=" { return(EQ); }
".." { return(DOUBLEDOT); }
{unsigned_integer} { return(UNSIGNED_INTEGER); }
{real} { return(REAL); }
{hex_integer} { return(HEX_INTEGER); }
{string} { return{STRING}; }
{bad_string} { System.err.println("Unterminated string"); }
{identifier} { return(IDENTIFIER); }
[*/+\-,^.;:()\[\]] { return(yycharat(0)); }
{white_space} { }
\n { line_number += 1; }
. { System.err.println("Illegal input"); }
動作未確認
!2007-08-07 Tue
flex/examples/fastwc/wc5.l
%%
%{
private int cc = 0, wc = 0, lc = 0;
%}
%class Lexer
%unicode
%line
%column
%standalone
ws = [ \t]
nonws = [^ \t\n]
word = {ws}*{nonws}+
words = {word}{ws}+
%%
{word}{ws}* { cc += yylength(); wc++; }
{word}{ws}*\n { cc += yylength(); wc++; lc++; }
{words}{word} { cc += yylength(); wc += 2; } /* oops */
{words}{2}{word}{ws}* { cc += yylength(); wc += 3; }
{words}{3}{word}{ws}* { cc += yylength(); wc += 4; }
{ws}+ { cc += yylength(); }
\n+ { cc += yylength(); lc += yylength(); }
<> { System.out.println(lc + " " + wc + " " + cc); return YYEOF; }
で、
a
a a
a a a
a a a a
a a a a a
を入力すると、
5 15 30
!2007-08-06 Mon
flex/examples/fastwc/wc4.l
%%
%{
private int cc = 0, wc = 0, lc = 0;
%}
%class Lexer
%unicode
%line
%column
%standalone
ws = [ \t]
nonws = [^ \t\n]
word = {ws}*{nonws}+
words = {word}{ws}+
%%
{word}{ws}* { cc += yylength(); wc++; }
{word}{ws}*\n { cc += yylength(); wc++; lc++; }
{words}{word}{ws}* { cc += yylength(); wc += 2; }
{words}{word}{ws}*\n { cc += yylength(); wc += 2; lc++; }
{words}{2}{word}{ws}* { cc += yylength(); wc += 3; }
{words}{2}{word}{ws}*\n { cc += yylength(); wc += 3; lc++; }
{words}{3}{word}{ws}* { cc += yylength(); wc += 4; }
{words}{3}{word}{ws}*\n { cc += yylength(); wc += 4; lc++; }
{ws}+ { cc += yylength(); }
\n+ { cc += yylength(); lc += yylength(); }
<> { System.out.println(lc + " " + wc + " " + cc); return YYEOF; }
で、
a
a a
a a a
a a a a
a a a a a
を入力すると、
5 15 30
!2007-08-05 Sun
flex/examples/fastwc/wc3.l
%%
%{
private int cc = 0, wc = 0, lc = 0;
%}
%class Lexer
%unicode
%line
%column
%standalone
ws = [ \t]
nonws = [^ \t\n]
word = {ws}*{nonws}+
words = {word}{ws}+
%%
{word}{ws}* { cc += yylength(); wc++; }
{word}{ws}*\n { cc += yylength(); wc++; lc++; }
{words}{word}{ws}* { cc += yylength(); wc += 2; }
{words}{2}{word}{ws}* { cc += yylength(); wc += 3; }
{words}{3}{word}{ws}* { cc += yylength(); wc += 4; }
{ws}+ { cc += yylength(); }
\n+ { cc += yylength(); lc += yylength(); }
<> { System.out.println(lc + " " + wc + " " + cc); return YYEOF; }
で、
a bc def ghij
klmno pqrstu
を入力すると、
2 6 27
入力が良くなかったか…
勘違いしていた
!2007-08-04 Sat
flex/examples/fastwc/wc2.l
%%
%{
private int cc = 0, wc = 0, lc = 0;
%}
%class Lexer
%unicode
%line
%column
%standalone
ws = [ \t]
nonws = [^ \t\n]
word = {ws}*{nonws}+
%%
{word}{ws}* { cc += yylength(); wc++; }
{word}{ws}*\n { cc += yylength(); wc++; lc++; }
{ws}+ { cc += yylength(); }
\n+ { cc += yylength(); lc += yylength(); }
<> { System.out.println(lc + " " + wc + " " + cc); return YYEOF; }
で、
abc def ghi
jkl
mno
を入力すると、
3 5 20
!2007-08-03 Fri
flex/examples/fastwc/wc1.l
%%
%{
private int cc = 0, wc = 0, lc = 0;
%}
%class Lexer
%unicode
%line
%column
%standalone
ws = [ \t]
nonws = [^ \t\n]
%%
{nonws}+ { cc += yylength(); wc++; }
{ws}+ { cc += yylength(); }
\n { lc++; cc++; }
<> { System.out.println(lc + " " + wc + " " + cc); return YYEOF; }
で、
abc def ghi
jkl
mno
を入力すると、
3 5 20
!2007-08-02 Thu
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println("*foo*"); }
bar { System.out.println("1" + yytext() + "1");
yypushback(1);
System.out.println("2" + yytext() + "2"); }
で、
foobar
を入力すると、
*foo*
1bar1
2ba2
r
!2007-08-01 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println("*foo*"); }
bar { yypushback(1); }
で、
foobar
を入力すると、
*foo*
r
!2007-07-31 Tue
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println("*foo*"); }
b { yypushback(1); }
ob { System.out.println("*ob*"); }
で、
foobar
を入力すると、
*foo*
で無限ループ
あれ?と思ったが、b が戻って、また b 、また b また b ...
となっているだけか…
!2007-07-30 Mon
//import JFlex.*;
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
b { yypushStream(new java.io.FileReader("bar")); }
<> { if (yymoreStreams()) yypopStream(); else return YYEOF; }
コンパイルできなかった…
!2007-07-29 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
b { yyreset(new java.io.FileReader("bar")); }
で、
foobar
を入力すると、
foo
を無限に出力…
あれ?どうすれば?
!2007-07-28 Sat
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
b { yyreset(yy_reader); }
で、
foobar
を入力すると、
foo
を無限に出力…
current のリーダーを与えることがそもそも間違っているか…
!2007-07-27 Fri
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
r { yyclose(); }
で、
foobar
を入力すると、
fooba
!2007-07-26 Thu
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println(yycharat(0)); }
で、
foobar
を入力すると、
f
bar
!2007-07-25 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println(yylength()); }
で、
foobar
を入力すると、
3
bar
!2007-07-24 Tue
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
abcdef { System.out.println("abcdef"); }
abc/DEF { System.out.println("abcDEF"); }
で、
abcdef
abcDEF
abc
を入力すると、
abcdef
abcDEF
DEF
abc
「/」は使えないという気がしていたが、中田先生のところに
JFlexではマッチング条件の指定「a/b」は使えない。
という記述があったからか?
昔は使えなかったのかもしれない。
!2007-07-23 Mon
%%
%class Lexer
%unicode
%line
%column
%standalone
%x state1
%%
a { yybegin(state1); }
<> { System.out.println("*EOF*"); return YYEOF; }
. { System.out.println("*others*"); }
で、
abc
を入力すると、
bc
*EOF*
!2007-07-22 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
<> { System.out.println("*EOF*"); return YYEOF; }
. { System.out.println("*others*"); }
で、
abc
を入力すると、
*others*
*others*
*others*
*EOF*
「return YYEOF;」を入れないと、無限ループに…
!2007-07-21 Sat
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
a { System.out.println("*a*"); }
"\n" { System.out.println("*\\n*"); }
. { System.out.println("*others*"); }
で、
ab
を入力すると、
*a*
*others*
*\n*
!2007-07-20 Fri
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
a { System.out.println("*a*"); }
. { System.out.println("*others*"); }
\n { System.out.println("*\\n*"); }
で、
ab
を入力すると、
*a*
*others*
*\n*
!2007-07-19 Thu
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
a { System.out.println("*a*"); }
\n { System.out.println("*\\n*"); }
. { System.out.println("*others*"); }
で、
ab
を入力すると、
*a*
*others*
*\n*
!2007-07-18 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
((a)) { System.out.println("*a*"); }
((b)) { System.out.println("*b*"); }
. { System.out.println("*others*"); }
で、
abc
を入力すると、
*a*
*b*
*others*
!2007-07-17 Tue
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
(a) { System.out.println("*a*"); }
(b) { System.out.println("*b*"); }
. { System.out.println("*others*"); }
で、
abc
を入力すると、
*a*
*b*
*others*
!2007-07-16 Mon
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
"/*"~"*/" { System.out.println("*" + yytext() + "*"); }
. { System.out.println("*others*"); }
で、
a
/* comment */
を入力すると、
*others*
*/* comment */*
!2007-07-15 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
![:uppercase:] { System.out.println("*!uppercase*"); }
![:lowercase:] { System.out.println("*!lowercase*"); }
. { System.out.println("*others*"); }
で、
Aa_ 1
を入力すると、
*!uppercase*
?
a
を入力すると(改行なし)、
*!uppercase*
A
を入力すると(改行なし)、
*!lowercase*
処理時、以下が出ていた
Warning in file "20070715_jflex00.l" (line 20):
Rule can never be matched:
. { System.out.println("*others*"); }
!2007-07-14 Sat
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
[:uppercase:] { System.out.println("*uppercase*"); }
[:lowercase:] { System.out.println("*lowercase*"); }
. { System.out.println("*others*"); }
で、
Aa_ 1
を入力すると、
*uppercase*
*lowercase*
*others*
*others*
*others*
!2007-07-13 Fri
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
[:digit:] { System.out.println("*digit*"); }
. { System.out.println("*others*"); }
で、
a_ 1
を入力すると、
*others*
*others*
*others*
*digit*
!2007-07-12 Thu
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
[:letter:] { System.out.println("*letter*"); }
. { System.out.println("*others*"); }
で、
a_ 1
を入力すると、
*letter*
*others*
*others*
*others*
!2007-07-11 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
[:jletterdigit:] { System.out.println("*jletterdigit*"); }
. { System.out.println("*others*"); }
で、
a_ 1
を入力すると、
*jletterdigit*
*jletterdigit*
*others*
*jletterdigit*
!2007-07-10 Tue
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
[:jletter:] { System.out.println("*jletter*"); }
. { System.out.println("*others*"); }
で、
a_ 1
を入力すると、
*jletter*
*jletter*
*others*
*others*
!2007-07-09 Mon
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
" "" " { System.out.print("*space2*"); }
で、
foo bar hoge
を入力すると、
foo bar*space2*hoge
!2007-07-08 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
" " { System.out.print("*space2*"); }
で、
foo bar hoge
を入力すると、
foo bar*space2*hoge
!2007-07-07 Sat
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
' ' { System.out.print("*space*"); }
で、
foo bar
を入力すると、
foo bar
foo bar ' 'aa'
を入力すると、
foo bar ' 'aa'
ありゃりゃ、結局、どういう意味になっているんだろうか?
!2007-07-06 Fri
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
" " { System.out.print("*space*"); }
で、
foo bar
を入力すると、
foo*space*bar
!2007-07-05 Thu
自己ループ
%%
%class Lexer
%unicode
%line
%column
%standalone
macro1 = {macro1}
%%
{macro1} { System.out.print("macro1"); }
で、
Macro macro1 contains a cycle
1 error, 0 warnings.
!2007-07-04 Wed
循環
%%
%class Lexer
%unicode
%line
%column
%standalone
macro1 = (a|b)
macro2 = {macro3}
macro3 = {macro1}|{macro2}
%%
{macro3} { System.out.print("macro3"); }
で、
Macro macro3 contains a cycle
1 error, 0 warnings.
!2007-07-03 Tue
順番の確認
%%
%class Lexer
%unicode
%line
%column
%standalone
macro3 = {macro1}|{macro2}
macro1 = (a|b)
macro2 = (b|c)
%%
{macro3} { System.out.print("macro3"); }
で、
abc
を入力すると、
macro3macro3macro3
!2007-07-02 Mon
%%
%class Lexer
%unicode
%line
%column
%standalone
macro = (^a)
%%
{macro}* { System.out.print("^a"); }
で、
Error in file "20070702_jflex00.l" (line 25):
Syntax error.
macro = (^a)
^
「^」を含んでいるからエラーなのか???
^ 演算子や $ 演算子を含んでいてはならない
という文があるんだけど、、、
flex のマニュアルにもダメと書いてあるようなので、ダメみたいだ
!2007-07-01 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
macro = a|b
%%
{macro}* { System.out.print("(a|b)*"); }
で、
aabbababfoo
を入力すると、
(a|b)*foo
flex も同じ挙動だった。JLex は違うの???
!2007-06-30 Sat
flex のときに使ったコード(2007-02-08 Thu)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%x COMMENT
%%
"{" { yybegin(COMMENT); }
{
"$R"
"$I"
"$M"
"}" { yybegin(YYINITIAL); }
}
で、
{$I-}
を入力すると、
$I-}
あれ?
「スタート状態のスコープ」という機能はないのかな?
(JFlex 1.4.1 でも同じ)
!2007-06-29 Fri
flex のときに使ったコード(2007-02-06 Tue)を活用
%%
%{
private int[] last_state = new int[10];
private int state_count = 0;
%}
%class Lexer
%unicode
%line
%column
%standalone
%x FOO BAR baz
%%
FOO {
last_state[state_count] = yystate();
System.out.println("foo:" + yystate());
state_count++;
yybegin(baz);
}
BAR {
last_state[state_count] = yystate();
System.out.println("bar:" + yystate());
state_count++;
yybegin(baz);
}
END {
System.out.println("end:" + yystate());
state_count--;
yybegin(last_state[state_count]);
}
で、
FOO
END
BAR
END
を入力すると、
foo:0
end:2
bar:0
end:2
!2007-06-28 Thu
flex のときに使ったコード(2007-02-05 Mon)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%x state1
%%
1 { yybegin(state1); }
one { System.out.print("two"); }
<*>three { System.out.print("four"); }
エラー。そんな機能(<*>)はないらしい
!2007-06-27 Wed
flex のときに使ったコード(2007-02-04 Sun)を活用
%%
%{
private int[] last_state = new int[10];
private int state_count = 0;
%}
%class Lexer
%unicode
%line
%column
%standalone
%x FOO BAR baz
%%
FOO {
last_state[state_count] = FOO;
state_count++;
yybegin(baz);
}
BAR {
last_state[state_count] = BAR;
state_count++;
yybegin(baz);
}
END {
state_count--;
yybegin(last_state[state_count]);
}
で、
FOO
FOO
BAR
END
END
を入力すると、
FOO
BAR
END
!2007-06-26 Tue
flex のときに使ったコード(2007-02-03 Sat)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%x PASCAL
%x C
%%
begin { return(OPEN_BLOCK); }
end { return(CLOSE_BLOCK); }
"{" { return(OPEN_BLOCK); }
"}" { return(CLOSE_BLOCK); }
「{」「}」だとエラーに。
!2007-06-25 Mon
flex のときに使ったコード(2007-02-02 Fri)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%x state1
%s state2
%%
1 { yybegin(state1); }
2 { yybegin(state2); }
"something" { System.out.print("SOMETHING"); }
"another thing" { System.out.print("ANOTHER THING"); }
"something else" { System.out.print("SOMETHING ELSE"); }
で、
something
1 something
another thing
something else
2 something
another thing
something else
を入力すると、
something
SOMETHING
another thing
SOMETHING ELSE
something
ANOTHER THING
SOMETHING ELSE
!2007-06-24 Sun
flex のときに使ったコード(2007-02-01 Thu)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%x state1
%s state2
%%
"something" {}
"another thing" {}
"something else" {}
* flex では「 "something"」のようにスペースがあると怒られたようだが、jflex では大丈夫
* flex では「」のようにスペースがあると怒られたようだが、jflex では大丈夫
!2007-06-23 Sat
flex のときに使ったコード(2007-01-30 Tue)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%x COMMENT
%%
"{" { yybegin(COMMENT); }
"$R" { }
"$I" { }
"$M" { }
"}" { yybegin(YYINITIAL); }
で、
{$I-}
を入力すると、
-
!2007-06-22 Fri
flex のときに使ったコード(2007-01-29 Mon)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%x state1
%%
@ { yybegin(state1); }
"one" { System.out.print("two"); }
"three" { System.out.print("four"); }
- { yybegin(YYINITIAL); }
で、
three
@one three -three
を入力すると、
four
two three four
「INITIAL」は「YYINITIAL」
!2007-06-21 Thu
flex のときに使ったコード(2007-01-28 Sun)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%x state1
%%
@ { yybegin(state1); }
"one" { System.out.print("two"); }
"three" { System.out.print("four"); }
で、
three
@one three
を入力すると、
four
two three
!2007-06-20 Wed
flex のときに使ったコード(2007-01-27 Sat)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%s state1
%%
@ { yybegin(state1); }
"one" { System.out.print("two"); }
"three" { System.out.print("four"); }
で、
three
@one three
を入力すると、
four
two four
「BEGIN()」は「yybegin()」
!2007-06-19 Tue
flex のときに使ったコード(2007-01-26 Fri)を活用
%%
%class Lexer
%unicode
%line
%column
%standalone
%x state1
%s state2
%x state3 state4
%%
"foo" {}
"bar" {}
"bar" {}
* 改めて見てみると「%%」の位置と書いている内容が flex と違わない?
* 「%x」、「%s」は「%xstate」「%state」でも良し
* 「{}」を省略できないのを忘れていて、はじめエラーに…
!2007-06-18 Mon
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println("*FOO*" + ":" + yycolumn); }
で、
foofoo
を入力すると、
*FOO*:0
*FOO*:3
!2007-06-17 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println("*FOO*" + ":" + yyline); }
で、
foo
foo
を入力すると、
*FOO*:0
*FOO*:1
「%line」をつけないと、両方とも「*FOO*:0」
!2007-06-16 Sat
%%
%class Lexer
%unicode
%line
%column
%standalone
%char
%%
foo { System.out.println("*FOO*" + ":" + yychar); }
で、
foofoo
を入力すると、
*FOO*:0
*FOO*:3
「%char」をつけないと、両方とも「*FOO*:0」
!2007-06-15 Fri
%%
%class Lexer
%unicode
%line
%column
%standalone
%caseless
%%
foo { System.out.println("*FOO*"); }
で、
Foo
を入力すると、
*FOO*
!2007-06-14 Thu
%%
%class Lexer
//%unicode
%line
%column
%standalone
//%8bit
%full
%%
foo { System.out.println("*FOO*"); }
で、
あ
を入力すると、
Unexpected exception:
java.lang.ArrayIndexOutOfBoundsException
at Lexer.yylex(Lexer.java:475)
at Lexer.main(Lexer.java:531)
あれ?期待と違った…
「255より大きいコードの入力文字」って何?
!2007-06-13 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
%7bit
%%
foo { System.out.println("*FOO*"); }
で、
あ
を入力すると、
あ
ArrayIndexOutofBoundsException が発生しないぞ?と思ったら、
「%unicode」がついているからのようだ。
「%unicode」をコメントアウトして実行すると、以下のエラー
Unexpected exception:
java.lang.ArrayIndexOutOfBoundsException
at Lexer.yylex(Lexer.java:467)
at Lexer.main(Lexer.java:523)
!2007-06-12 Tue
%%
%class Lexer
%unicode
%line
%column
%standalone
%pack
%%
foo { System.out.println("*FOO*"); }
* ルールがなさ過ぎのせいか何も変化なし
* switch, table, pack の関係(併用姓)がいまいち良く分からないな。困ったときにまた調べるべし
!2007-06-11 Mon
%%
%class Lexer
%unicode
%line
%column
%standalone
%table
%%
foo { System.out.println("*FOO*"); }
yy_unpack() というメソッドがなくなるようだ
!2007-06-10 Sun
「%cup*」関係、「%byacc」はあとで見ることにする
%%
%class Lexer
%unicode
%line
%column
%standalone
%switch
%%
foo { System.out.println("*FOO*"); }
* テーブルの代りに switch 文にするのかな?
* JFlex 1.3.5 でも実装されているようだ。
!2007-06-09 Sat
%%
%class Lexer
%unicode
%line
%column
//%standalone
%%
foo { System.out.println("*FOO*"); }
で、「%standalone」がないと、
main がなかったり違いが出る
!2007-06-08 Fri
%%
%class Lexer
%unicode
%line
%column
%standalone
%debug
%%
foo { System.out.println("*FOO*"); }
で、
***************
*** 21,26 ****
--- 21,27 ----
/** initial size of the lookahead buffer */
final private static int YY_BUFFERSIZE = 16384;
+ final private static String yy_NL = System.getProperty("line.separator");
/** lexical states */
final public static int YYINITIAL = 0;
***************
*** 499,508 ****
--- 500,513 ----
switch (yy_action) {
case 4:
+ System.out.println("line: "+(yyline+1)+" "+"col: "+(yycolumn+1)+" "+"match: --"+yytext()+"--");
+ System.out.println("action [20] { System.out.println(\"*FOO*\"); }");
{ System.out.println("*FOO*"); }
case 6: break;
case 1:
case 2:
+ System.out.println("line: "+(yyline+1)+" "+"col: "+(yycolumn+1)+" "+"match: --"+yytext()+"--");
+ System.out.println("action [2147483647] {System.out.print(yytext());}");
{ System.out.print(yytext()); }
case 7: break;
default:
という違い
!2007-06-07 Thu
%%
%class Lexer
%unicode
%line
%column
%standalone
%eof{
System.out.println("*eof*");
%eof}
%eofclose false
%%
foo { System.out.println("*FOO*"); }
で、
「%eofclose」を無効にするということらしい。
なぜ、このオプションにだけそういう機能が含まれているのだろうか?
(e.g. in case closing of input stream is not wanted after %cup)
っていうのが関係?
JFlex 1.3.5 だとエラー。1.4.1 だと OK
!2007-06-06 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
//%eof{
// System.out.println("*eof*");
//%eof}
%eofclose
%%
foo { System.out.println("*FOO*"); }
「%eof{」有効、「%eofclose」無効と
「%eof{」無効、「%eofclose」有効の差は、
***************
*** 375,385 ****
* Contains user EOF-code, which will be executed exactly once,
* when the end of file is reached
*/
! private void yy_do_eof() {
if (!yy_eof_done) {
yy_eof_done = true;
! System.out.println("*eof*");
!
}
}
--- 375,384 ----
* Contains user EOF-code, which will be executed exactly once,
* when the end of file is reached
*/
! private void yy_do_eof() throws java.io.IOException {
if (!yy_eof_done) {
yy_eof_done = true;
! yyclose();
}
}
!2007-06-05 Tue
%%
%class Lexer
%unicode
%line
%column
%standalone
%eof{
System.out.println("*eof*");
%eof}
%eofthrow{
exception1, exception2
%eofthrow}
%%
foo { System.out.println("*FOO*"); }
で、
private void yy_do_eof()
↓
private void yy_do_eof() throws exception1, exception2
という差
「%eof」がないと生成されなかった
!2007-06-04 Mon
%%
%class Lexer
%unicode
%line
%column
%standalone
%eofval{
System.out.println("*eofval*");
return YYEOF;
%eofval}
%eof{
System.out.println("*eof*");
%eof}
%%
foo { System.out.println("*FOO*"); }
で、
foo
を入力すると、
*FOO*
*eof*
*eofval*
!2007-06-03 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
%eof{
System.out.println("*eof*");
%eof}
%%
foo { System.out.println("*FOO*"); }
で、
foo
を入力すると、
*FOO*
*eof*
!2007-06-02 Sat
%%
%class Lexer
%unicode
%line
%column
%standalone
%eofval{
System.out.println("*eofval*");
return YYEOF;
%eofval}
%%
foo { System.out.println("*FOO*"); }
で、
foo
を入力すると、
*FOO*
*eofval*
!2007-06-01 Fri
%%
%class Lexer
%unicode
%line
%column
%standalone
%eofval{
System.out.println("*eofval*");
%eofval}
%%
foo { System.out.println("*FOO*"); }
で、
foo
を入力すると、
*FOO*
*eofval*
*eofval*
...
無限ループ?
!2007-05-31 Thu
%%
%class Lexer
%unicode
%line
%column
%standalone
%yylexthrow exception1 , exception2
%%
foo { System.out.println("*FOO*"); }
で、
public int yylex() throws java.io.IOException {
↓
public int yylex() throws java.io.IOException, exception1 , exception2 {
という差
!2007-05-30 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
%yylexthrow{
exception1 , exception2
%yylexthrow}
%%
foo { System.out.println("*FOO*"); }
で、
public int yylex() throws java.io.IOException {
↓
public int yylex() throws java.io.IOException, exception1 , exception2
{
という差
!2007-05-29 Tue
%%
%class Lexer
%unicode
%line
%column
%standalone
%type String
%%
foo { System.out.println("*FOO*"); }
で、
public int yylex() throws java.io.IOException {
↓
public String yylex() throws java.io.IOException {
という差
!2007-05-28 Mon
%%
%class Lexer
%unicode
%line
%column
%standalone
%intwrap
%%
foo { System.out.println("*FOO*"); }
動作不明…
!2007-05-27 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
%integer
%%
foo { System.out.println("*FOO*"); }
で、
何も差が出ていないような?
!2007-05-26 Sat
%%
%class Lexer
%unicode
%line
%column
%standalone
%function YYLEX
%%
foo { System.out.println("*FOO*"); }
で、
public int yylex() throws java.io.IOException {
while ( !scanner.yy_atEOF ) scanner.yylex();
の yylex が YYLEX に
!2007-05-25 Fri
%%
%class Lexer
%unicode
%line
%column
%standalone
// ???
//%include "20070525_jflex01.l"
%include 20070525_jflex01.l
で、なぜかエラー
Including "20070525_jflex01.l"
java.lang.ArrayIndexOutOfBoundsException
1.4.1 でも別のエラー
Including "20070525_jflex01.l"
Error in file "20070525_jflex00.l" (line 18):
Syntax error.
%include 20070525_jflex01.l
^
1 error, 0 warnings.
!2007-05-24 Thu
%%
%class Lexer
%unicode
%line
%column
%standalone
%buffer 32768
%%
foo { System.out.println("*FOO*"); }
で、
final private static int YY_BUFFERSIZE = 16384;
↓
final private static int YY_BUFFERSIZE = 32768;
という差
!2007-05-23 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
%scanerror exception
%%
foo { System.out.println("*FOO*"); }
で、
***************
*** 339,345 ****
*
* @param errorCode the code of the errormessage to display
*/
! private void yy_ScanError(int errorCode) {
String message;
try {
message = YY_ERROR_MSG[errorCode];
--- 339,345 ----
*
* @param errorCode the code of the errormessage to display
*/
! private void yy_ScanError(int errorCode) throws exception {
String message;
try {
message = YY_ERROR_MSG[errorCode];
***************
*** 348,354 ****
message = YY_ERROR_MSG[YY_UNKNOWN_ERROR];
}
! throw new Error(message);
}
--- 348,354 ----
message = YY_ERROR_MSG[YY_UNKNOWN_ERROR];
}
! throw new exception(message);
}
***************
*** 360,366 ****
* @param number the number of characters to be read again.
* This number must not be greater than yylength()!
*/
! private void yypushback(int number) {
if ( number > yylength() )
yy_ScanError(YY_PUSHBACK_2BIG);
--- 360,366 ----
* @param number the number of characters to be read again.
* This number must not be greater than yylength()!
*/
! private void yypushback(int number) throws exception {
if ( number > yylength() )
yy_ScanError(YY_PUSHBACK_2BIG);
***************
*** 375,381 ****
* @return the next token
* @exception IOException if any I/O-Error occurs
*/
! public int yylex() throws java.io.IOException {
int yy_input;
int yy_action;
--- 375,381 ----
* @return the next token
* @exception IOException if any I/O-Error occurs
*/
! public int yylex() throws java.io.IOException, exception {
int yy_input;
int yy_action;
という違い
!2007-05-22 Tue
%%
%class Lexer
%unicode
%line
%column
%standalone
%initthrow exception1, exception2
%%
foo { System.out.println("*FOO*"); }
で、
***************
*** 132,138 ****
*
* @param in the java.io.Reader to read input from.
*/
! Lexer(java.io.Reader in) {
this.yy_reader = in;
}
--- 132,138 ----
*
* @param in the java.io.Reader to read input from.
*/
! Lexer(java.io.Reader in) throws exception1, exception2 {
this.yy_reader = in;
}
***************
*** 142,148 ****
*
* @param in the java.io.Inputstream to read input from.
*/
! Lexer(java.io.InputStream in) {
this(new java.io.InputStreamReader(in));
}
--- 142,148 ----
*
* @param in the java.io.Inputstream to read input from.
*/
! Lexer(java.io.InputStream in) throws exception1, exception2 {
this(new java.io.InputStreamReader(in));
}
という違い
!2007-05-21 Mon
%%
%class Lexer
%unicode
%line
%column
%standalone
%initthrow{
exception1, exception2
%initthrow}
%%
foo { System.out.println("*FOO*"); }
で、
***************
*** 132,138 ****
*
* @param in the java.io.Reader to read input from.
*/
! Lexer(java.io.Reader in) {
this.yy_reader = in;
}
--- 132,139 ----
*
* @param in the java.io.Reader to read input from.
*/
! Lexer(java.io.Reader in) throws exception1, exception2
! {
this.yy_reader = in;
}
***************
*** 142,148 ****
*
* @param in the java.io.Inputstream to read input from.
*/
! Lexer(java.io.InputStream in) {
this(new java.io.InputStreamReader(in));
}
--- 143,150 ----
*
* @param in the java.io.Inputstream to read input from.
*/
! Lexer(java.io.InputStream in) throws exception1, exception2
! {
this(new java.io.InputStreamReader(in));
}
という違い
!2007-05-20 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
%initthrow{
"exception1"
%initthrow}
%%
foo { System.out.println("*FOO*"); }
で、
***************
*** 132,138 ****
*
* @param in the java.io.Reader to read input from.
*/
! Lexer(java.io.Reader in) {
this.yy_reader = in;
}
--- 132,139 ----
*
* @param in the java.io.Reader to read input from.
*/
! Lexer(java.io.Reader in) throws "exception1"
! {
this.yy_reader = in;
}
***************
*** 142,148 ****
*
* @param in the java.io.Inputstream to read input from.
*/
! Lexer(java.io.InputStream in) {
this(new java.io.InputStreamReader(in));
}
--- 143,150 ----
*
* @param in the java.io.Inputstream to read input from.
*/
! Lexer(java.io.InputStream in) throws "exception1"
! {
this(new java.io.InputStreamReader(in));
}
という違い
文字列で良いの???
!2007-05-19 Sat
%%
%class Lexer
%unicode
%line
%column
%standalone
%init{
// foo
%init}
%%
foo { System.out.println("*FOO*"); }
で、
「%{」では
class Lexer {
内に出力されるが、「%init{」では
Lexer(java.io.Reader in) {
// foo
this.yy_reader = in;
}
のように出力されるようだ
「%init {」のように空白を置いてはダメのようだ。
!2007-05-18 Fri
JFlex 1.3.5 に「%apiprivate」はないようだ
1.4.1 を使うと、
%%
%class Lexer
%unicode
%line
%column
%standalone
%apiprivate
%%
foo { System.out.println("*FOO*"); }
で、以下の public が private になるようだ
public static final int YYEOF = -1;
public static final int YYINITIAL = 0;
public final void yyclose() throws java.io.IOException {
public final void yyreset(java.io.Reader reader) {
public final int yystate() {
public final void yybegin(int newState) {
public final String yytext() {
public final char yycharat(int pos) {
public final int yylength() {
public void yypushback(int number) {
public int yylex() throws java.io.IOException {
!2007-05-17 Thu
%%
%class Lexer
%unicode
%line
%column
%standalone
%abstract
%%
foo { System.out.println("*FOO*"); }
で、
class Lexer {
と
abstract class Lexer {
の違い
!2007-05-16 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
%final
%%
foo { System.out.println("*FOO*"); }
で、
class Lexer {
と
final class Lexer {
の違い
!2007-05-15 Tue
「%implements」良く分かりませんな〜
%%
%class Lexer
%unicode
%line
%column
%standalone
%public
%%
foo { System.out.println("*FOO*"); }
で、
***************
*** 132,138 ****
*
* @param in the java.io.Reader to read input from.
*/
! Lexer(java.io.Reader in) {
this.yy_reader = in;
}
--- 132,138 ----
*
* @param in the java.io.Reader to read input from.
*/
! public Lexer(java.io.Reader in) {
this.yy_reader = in;
}
***************
*** 142,148 ****
*
* @param in the java.io.Inputstream to read input from.
*/
! Lexer(java.io.InputStream in) {
this(new java.io.InputStreamReader(in));
}
--- 142,148 ----
*
* @param in the java.io.Inputstream to read input from.
*/
! public Lexer(java.io.InputStream in) {
this(new java.io.InputStreamReader(in));
}
という違い
!2007-05-14 Mon
「%class」がないと、Yylex.java が生成される
%%
//%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println("*FOO*"); }
で、
foo
を入力すると、
*FOO*
!2007-05-13 Sun
%%
%class Lexer
%unicode
%line
%column
%standalone
Identifier = [:jletter:] [:jletterdigit:]*
%%
{
foo { System.out.println("*foo*"); }
"bar" { System.out.println("*bar*"); }
}
で、
foo bar
を入力すると、
*foo*
*bar*
!2007-05-12 Sat
%%
%class Lexer
%unicode
%line
%column
%standalone
Identifier = [:jletter:] [:jletterdigit:]*
%%
break { System.out.println("*break*"); }
{Identifier} { System.out.println("*Identifier*"); }
で、
breaker break
を入力すると、
*Identifier*
*break*
!2007-05-11 Fri
%%
%class Lexer
%unicode
%line
%column
%standalone
%{
private void print(int x) {
System.out.println(x);
}
%}
%%
foo { print(yyline); }
で、
foo
foo
を入力すると、
0
1
!2007-05-10 Thu
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println(yycolumn); }
で、
foofoo
foo
を入力すると、
0
3
0
!2007-05-09 Wed
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println(yyline); }
で、
foofoo
foo
を入力すると、
0
0
1
!2007-05-08 Tue
「Java言語に対するJFlexの仕様書の一部」という例を
JFlex に通してみたが、CUP の使い方が分からない…
sym.* というシンボルがないと言われてしまう
先に進む
!!!2007-07-27 Fri
sym を自分で定義しろということなのか???
というより、本来 CUP が生成してくれるものっぽい
!2007-05-07 Mon
マクロ定義
%%
%class Lexer
%unicode
%line
%column
%standalone
DIGIT=[0-9]
LETTER=[a-z]
IDENT=[a-z_][a-z0-9]*
ALPHANUM={LETTER}|{DIGIT}
%%
{LETTER} { System.out.println("*" + yytext() + "*"); }
で、
abc123
を入力すると、
*a*
*b*
*c*
123
!2007-05-06 Sun
はじめての jflex
%%
%class Lexer
%unicode
%line
%column
%standalone
%%
foo { System.out.println("*FOO*"); }
で、
foobarfoo
を入力すると、
*FOO*
bar*FOO*
「{ }」は省略できないようだ
!2007-05-05 Sat
2007-05-02 ので -v をつけて生成してみた。
flex version 2.5.31 usage statistics:
scanner options: -vI8 -Cem
50/2000 NFA states
22/1000 DFA states (72 words)
9 rules
Compressed tables always back-up
3/40 start conditions
37 epsilon states, 19 double epsilon states
3/100 character classes needed 4/500 words of storage, 0 reused
64 state/nextstate pairs created
31/33 unique/duplicate transitions
28/1000 base-def entries created
37/2000 (peak 48) nxt-chk entries created
24/2500 (peak 36) template nxt-chk entries created
1 empty table entries
9 protos created
6 templates created, 10 uses
6/256 equivalence classes created
4/256 meta-equivalence classes created
0 (0 saved) hash collisions, 16 DFAs equal
0 sets of reallocations needed
392 total table entries needed
!2007-05-04 Fri
一昨日ので、-s をつけて生成してみた。
warning, -s option given but default rule can be matched
と言われたが、実行すると、
flex scanner jammed
!2007-05-03 Thu
スキャナとソケット とばし。
昨日ので -d つきで生成すると、
--(end of buffer or a NUL)
--accepting default rule ("a")
--accepting rule at line 21 ("
")
--accepting default rule ("b")
--accepting rule at line 21 ("
")
--accepting rule at line 13 ("/*")
--accepting rule at line 15 (" ")
--accepting rule at line 14 ("
")
--accepting rule at line 15 ("*/")
--accepting rule at line 14 ("
")
--accepting rule at line 15 (""")
--accepting rule at line 14 ("
")
--accepting rule at line 15 (""")
--accepting rule at line 14 ("
")
--(end of buffer or a NUL)
--EOF (start condition 1)
ab6
!2007-05-02 Wed
%{
int line_number = 0;
%}
%x COMMENT STRING
%%
"/*" BEGIN(COMMENT);
\n line_number += 1;
[^\n]*
"*/" BEGIN(INITIAL);
\" BEGIN(STRING);
\\\n line_number += 1;
[^\n\\\"]*
\" BEGIN(INITIAL);
\n line_number += 1;
%%
int main(int argc, char *argv)
{
yylex();
printf("%d\n", line_number);
}
で、
a
b
/*
*/
"
"
を入力すると、
ab6
* 「linenumber」と「line_number」が混在している(ようは間違い)。オンラインでも書籍でも間違っているようだ。
* 「\" BEGIN(STRING)」は「;」が抜けている…
* 「"*/" BEGIN(INITIAL);」は「warning, rule cannot be matched」と言われたが?
!2007-05-01 Tue
replace.lex
で、
yyXX
YYXX
を $ ./a.out myscan_ MYSCAN_ < foo と入力すると、
myscan_XX
MYSCAN_XX
!2007-04-30 Mon
numbers.lex
で、
10
1.2
.2
1e+2
1.2e+2
0xf
を入力すると、
yytext : 10
Type of number : SIGNED LONG
Value of number : 10
yytext : 1.2
Type of number : LONG DOUBLE
Value of number : 1.200000
yytext : .2
Type of number : LONG DOUBLE
Value of number : 0.200000
yytext : 1
Type of number : SIGNED LONG
Value of number : 1
e+yytext : 2
Type of number : SIGNED LONG
Value of number : 2
yytext : 1.2e+2
Type of number : LONG DOUBLE
Value of number : 120.000000
yytext : 0xf
Type of number : SIGNED LONG
Value of number : 15
!2007-04-29 Sun
string2.lex
で、
"foo"
"foo\""
"'foo'"
を入力すると、
string = "foo"
string = "foo""
string = "'foo'"
!2007-04-28 Sat
string1.lex
で、
"foo"
"foo\""
"'foo'"
を入力すると、
String = "foo"
String = "foo""
String = "'foo'"
!2007-04-27 Fri
%{
void yyerror(char *message);
%}
%x COMMENT
%%
"/*" BEGIN(COMMENT);
[^*\n]*
[^*\n]*\n
"*"+[^*/\n]* /* 余分な*を探す */
"*"+[^*/\n]*\n
<> yyerror("EOF in comment");
"*"+"/" BEGIN(INITIAL);
%%
void yyerror(char *message)
{
fprintf(stderr,"Error: \"%s\" in line %d. Token = %s\n",
message, yylineno, yytext);
exit(1);
}
で、
foo bar baz
/* comment */
を入力すると、
foo bar baz
!2007-04-26 Thu
%{
void yyerror(char *message);
%}
%x COMMENT
%%
"/*" BEGIN(COMMENT);
[^\n]
\n
<> yyerror("EOF in comment");
"*/" BEGIN(INITIAL);
%%
void yyerror(char *message)
{
fprintf(stderr,"Error: \"%s\" in line %d. Token = %s\n",
message, yylineno, yytext);
exit(1);
}
で、
foo bar baz
/* comment */
を入力すると、
foo bar baz
!2007-04-25 Wed
%%
#comment
%%
だとコメント(非推奨らしいが)
%%
# comment
%%
だとコメントにならないようだ
!2007-04-24 Tue
%{
#include
%}
%%
%%
int main(int argc, char *argv)
{
#ifdef FLEX_SCANNER
printf("FLEX_SCANNER\n");
#endif
}
で、
FLEX_SCANNER
!2007-04-23 Mon
j2t.lex
以下の箇所で warning が出たのだが?
"@" printf("@@");
"@" printf("@@");
!2007-04-22 Sun
pascal.lex
「.y」がないので…
!2007-04-21 Sat
wc.lex
foo は
foo bar baz
foo bar baz
で、
$ ./a.out -l -c -w foo
file : foo :lines 2 characters 24 words 6
-------------------------------------------------------------------------------
total : lines 2 characters 24 words 6
!2007-04-20 Fri
バックトラッキングを削除するためにルールを追加
%%
hurd return(GNU_OS);
hurdle return(JUMP);
hurdled return(JUMPED);
[a-z]+ return(OTHER);
%%
!2007-04-19 Thu
バックトラッキングを削除するためにルールを追加
%%
hurd return(GNU_OS);
hurdle return(JUMP);
hurdled return(JUMPED);
hu return(OTHER);
hur return(OTHER);
hurdl return(OTHER);
%%
!2007-04-18 Wed
「EOFルールは、スタート状態とのみ一緒に使うことができます」という表現はOK?
別の状態でも使えるような気がするのだが。言いたいことが違うのか?
NUL ってなんだ?C としては定義されていないっぽいけど
%%
hurd return(GNU_OS);
hurdle return(JUMP);
hurdled return(JUMPED);
%%
を「-b」つきで実行
lex.backup というファイルが生成された。中身↓
State #6 is non-accepting -
associated rule line numbers:
8 9 10
out-transitions: [ r ]
jam-transitions: EOF [ \000-q s-\377 ]
State #7 is non-accepting -
associated rule line numbers:
8 9 10
out-transitions: [ d ]
jam-transitions: EOF [ \000-c e-\377 ]
State #9 is non-accepting -
associated rule line numbers:
9 10
out-transitions: [ e ]
jam-transitions: EOF [ \000-d f-\377 ]
Compressed tables always back up.
!2007-04-17 Tue
yywrap の戻り値を 0 にしてみたら?
%{
#include
%}
%%
foo printf("*FOO*");
bar printf("*BAR*");
foobar printf("*FOOBAR*");
%%
int yywrap (void)
{
return 0;
}
int main(int argc, char *argv)
{
yyin = fopen("foo", "r");
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
yylex();
fclose(yyin);
yy_delete_buffer(YY_CURRENT_BUFFER);
}
で、foo が、
bar
foobar
foo
だと、
*BAR*
*FOOBAR*
*FOO*
を表示してプログラム停止
!2007-04-16 Mon
yy_flush_buffer なのために使うの?
yy_scan_string(), yy_scan_bytes(), yy_scan_buffer() あたりも良く分からないや〜
eof_rules.lex
で、
#include"file1.c"
#include "file2.c"
#include " file3.c"
を入力
file1.c が存在しないと、Unable to open "file1.c" のメッセージ
関係ないけど、include で指定するファイルに「"」が
含まれていても大丈夫のだろうか?
!2007-04-15 Sun
%{
#include
%}
%%
foo printf("*FOO*");
bar printf("*BAR*");
foobar printf("*FOOBAR*");
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
yyin = fopen("foo", "r");
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
yylex();
fclose(yyin);
yy_delete_buffer(YY_CURRENT_BUFFER);
yyin = fopen("bar", "r");
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
yylex();
fclose(yyin);
yy_delete_buffer(YY_CURRENT_BUFFER);
}
yy_delete_buffer は fclose の前でも後でも良いのだろうか?
内部の buffer 領域の解放なのかな?
!2007-04-14 Sat
翻訳テーブルの説明さっぱり良く分からないや。
互換性のためだけのようだからとばし。
%{
#include
%}
%%
foo printf("*FOO*");
bar printf("*BAR*");
foobar printf("*FOOBAR*");
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
yyin = fopen("foo", "r");
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
yylex();
fclose(yyin);
yyin = fopen("bar", "r");
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
yylex();
fclose(yyin);
}
で、foo が、
bar
foobar
foo
bar が、
foo
bar
foobar
だと、
*BAR*
*FOOBAR*
*FOO*
*FOO*
*BAR*
*FOOBAR*
!2007-04-13 Fri
「-i」つきで
%%
BEGIN printf("BEGIN_SYM"); /*return(BEGIN_SYM);*/
END printf("END_SYM"); /*return(END_SYM);*/
%%
で、
begin end
を入力すると、
BEGIN_SYM END_SYM
!2007-04-12 Thu
A [aA]
B [bB]
D [dD]
E [eE]
G [gG]
I [iI]
N [nN]
/* ... */
Z [zZ]
%%
{B}{E}{G}{I}{N} printf("BEGIN_SYM"); /*return(BEGIN_SYM);*/
{E}{N}{D} printf("END_SYM"); /*return(END_SYM);*/
%%
で、
begin end
を入力すると、
BEGIN_SYM END_SYM
!2007-04-11 Wed
%option c++
%option yyclass="Foo"
%{
#include
#include
#include
using namespace std;
int yywrap (void);
class Foo : public yyFlexLexer {
virtual int yylex();
void LexerOutput(const char* buf, int size) {
cout << "+" << size << "+";
}
};
%}
%%
foo *yyout << "*FOO*";
bar *yyout << "*BAR*";
foobar *yyout << "*FOOBAR*";
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new Foo;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
*BAR*+1+*FOOBAR*+1+*FOO*+1+
!2007-04-10 Tue
%option c++
%option yyclass="Foo"
%{
#include
#include
#include
using namespace std;
int yywrap (void);
class Foo : public yyFlexLexer {
virtual int yylex();
void LexerOutput(const char* buf, int size) {
cout << "+" << buf << "+";
}
};
%}
%%
foo *yyout << "*FOO*";
bar *yyout << "*BAR*";
foobar *yyout << "*FOOBAR*";
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new Foo;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
*BAR*+
+*FOOBAR*+
+*FOO*+
「スキャナの出力処理を変更」ってどういう意味なんだっけ?
良く分かっていない…
!2007-04-09 Mon
%option c++
%option yyclass="Foo"
%{
#include
#include
#include
using namespace std;
int yywrap (void);
class Foo : public yyFlexLexer {
virtual int yylex();
void LexerOutput(const char* buf, int size) {
cout << "+" << buf << "+";
}
};
%}
%%
foo cout << "*FOO*";
bar cout << "*BAR*";
foobar cout << "*FOOBAR*";
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new Foo;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
*BAR*+
+*FOOBAR*+
+*FOO*+
baz
を入力すると、
+b++a++z++
!2007-04-08 Sun
昨日はファイルを分けてみたが、分ける必要もなかったか?
%option c++
%option prefix="yy1"
%{
#include
#include
int yywrap (void);
using namespace std;
%}
%%
foo *yyout << "*FOO*";
bar *yyout << "*BAR*";
foobar *yyout << "*FOOBAR*";
%%
void foo(void)
{
FlexLexer* lexer = new yy1FlexLexer;
ifstream ifs("foo");
ofstream ofs("foo.out");
while(lexer->yylex(&ifs, &ofs) != 0)
;
}
と
%option c++
%option prefix="yy2"
%{
#include
#include
using namespace std;
int yywrap (void);
%}
%%
foo *yyout << "*foo*";
bar *yyout << "*bar*";
foobar *yyout << "*foobar*";
%%
void bar(void)
{
FlexLexer* lexer = new yy2FlexLexer;
ifstream ifs("bar");
ofstream ofs("bar.out");
while(lexer->yylex(&ifs, &ofs) != 0)
;
}
と
using namespace std;
void foo(void);
void bar(void);
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
foo();
bar();
return 0;
}
!2007-04-07 Sat
%option c++
%option prefix="yy1"
%{
#include
int yywrap (void);
using namespace std;
%}
%%
foo *yyout << "*FOO*";
bar *yyout << "*BAR*";
foobar *yyout << "*FOOBAR*";
%%
と
#include
#undef yyFlexLexer
#define yyFlexLexer yy1FlexLexer
#include
using namespace std;
void foo(void)
{
FlexLexer* lexer = new yy1FlexLexer;
ifstream ifs("foo");
ofstream ofs("foo.out");
while(lexer->yylex(&ifs, &ofs) != 0)
;
}
と
%option c++
%option prefix="yy2"
%{
#include
using namespace std;
int yywrap (void);
%}
%%
foo *yyout << "*foo*";
bar *yyout << "*bar*";
foobar *yyout << "*foobar*";
%%
と
#include
#undef yyFlexLexer
#define yyFlexLexer yy2FlexLexer
#include
using namespace std;
void bar(void)
{
FlexLexer* lexer = new yy2FlexLexer;
ifstream ifs("bar");
ofstream ofs("bar.out");
while(lexer->yylex(&ifs, &ofs) != 0)
;
}
と
using namespace std;
void foo(void);
void bar(void);
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
foo();
bar();
return 0;
}
複数の場合はこういう使い方するしかないかな?と思ったのだが、良い?
!2007-04-06 Fri
%option c++
%option prefix="yy1"
%{
#include
using namespace std;
int yywrap (void);
%}
%%
foo cout << "*FOO*";
bar cout << "*BAR*";
foobar cout << "*FOOBAR*";
%%
int yywrap (void)
{
return 1;
}
と
#undef yyFlexLexer
#define yyFlexLexer yy1FlexLexer
#include
using namespace std;
int main(int argc, char *argv)
{
FlexLexer* lexer = new yy1FlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
*BAR*
*FOOBAR*
*FOO*
!2007-04-05 Thu
%option c++
%option prefix="yy1"
%{
#include
#include
#include
using namespace std;
int yywrap (void);
// #undef yyFlexLexer
// #define yyFlexLexer yy1FlexLexer
// #include
%}
%%
foo cout << "*FOO*";
bar cout << "*BAR*";
foobar cout << "*FOOBAR*";
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yy1FlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
*BAR*
*FOOBAR*
*FOO*
複数のクラスを使うというのはどうやれば?
!2007-04-04 Wed
%option c++
%option yyclass="Foo"
%{
#include
#include
#include
using namespace std;
int yywrap (void);
class Foo : public yyFlexLexer {
virtual int yylex();
};
%}
%%
foo cout << "*FOO*";
bar cout << "*BAR*";
foobar cout << "*FOOBAR*";
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new Foo;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
*BAR*
*FOOBAR*
*FOO*
!2007-04-03 Tue
%option c++
%{
#include
#include
#include
using namespace std;
int yywrap (void);
%}
%%
foo *yyout << "*FOO*";
bar *yyout << "*BAR*";
foobar *yyout << "*FOOBAR*";
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
ifstream ifs("foo");
ofstream ofs("foo.out");
while(lexer->yylex(&ifs, &ofs) != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、ファイルに
*BAR*
*FOOBAR*
*FOO*
!2007-04-02 Mon
%option c++
%option yylineno
%{
#include
int yywrap (void);
using namespace std;
%}
%%
foo FLEX_STD cout << "*" << lineno() << " " << YYLeng() << " " << YYText();
bar FLEX_STD cout << "+" << lineno() << " " << YYLeng() << " " << YYText();
foobar FLEX_STD cout << "-" << lineno() << " " << YYLeng() << " " << YYText();
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
+1 3 bar
-1 6 foobar
*1 3 foo
「%option yylineno」の効用は?
!2007-04-01 Sun
%option c++
%{
#include
#include
#include
using namespace std;
int yywrap (void);
%}
%%
foo printf("*FOO*");
bar printf("*BAR*");
foobar printf("*FOOBAR*");
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
ifstream ifs("foo");
lexer->switch_streams(&ifs);
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
*BAR*
*FOOBAR*
*FOO*
!2007-03-31 Sat
%option c++
%{
#include
int yywrap (void);
using namespace std;
%}
%%
foo cout << "*" << lineno() << " " << YYLeng() << endl;
bar cout << "+" << lineno() << " " << YYLeng() << endl;
foobar cout << "-" << lineno() << " " << YYLeng() << endl;
\n yylineno++;
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
+1 3
-2 6
*3 3
!2007-03-30 Fri
%option c++
%{
#include
int yywrap (void);
using namespace std;
%}
%%
foo FLEX_STD cout << "*" << lineno() << " " << YYLeng() << " " << YYText();
bar FLEX_STD cout << "+" << lineno() << " " << YYLeng() << " " << YYText();
foobar FLEX_STD cout << "-" << lineno() << " " << YYLeng() << " " << YYText();
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
+1 3 bar
-1 6 foobar
*1 3 foo
!2007-03-29 Thu
%option c++
%{
#include
int yywrap (void);
//using namespace std;
%}
%%
foo FLEX_STD cout << "*" << YYText() << FLEX_STD endl;
bar FLEX_STD cout << "+" << YYText() << FLEX_STD endl;
foobar FLEX_STD cout << "-" << YYText() << FLEX_STD endl;
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
lexer->yylex();
return 0;
}
で、
bar
foobar
foo
を入力すると、
+bar
-foobar
*foo
!2007-03-28 Wed
ちょっと後戻り
%option c++
%{
#include
int yywrap (void);
%}
%%
foo std::cout << "*FOO*";
bar std::cout << "*BAR*";
foobar std::cout << "*FOOBAR*";
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
で、
bar
foobar
foo
を入力すると、
*BAR*
*FOOBAR*
*FOO*
ふと、FlexLexer って抽象クラスだぞと思ったら、
ちゃんと yyFlexLexer を new していたか。
!2007-03-27 Tue
yylex で指定した ostream を使う方法が良く分からないなあ〜
(2007-04-03 Tue で一応できたっぽい)
%option c++
%{
int yywrap (void);
%}
%%
foo printf("*FOO*");
bar printf("*BAR*");
foobar printf("*FOOBAR*");
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
printf("+%d+\n", lexer->lineno());
return 0;
}
で、
bar
foobar
foo
を入力すると、
*BAR*
*FOOBAR*
*FOO*
+1+
ありょ?
!2007-03-26 Mon
%option c++
%{
#include
#include
#include
using namespace std;
int yywrap (void);
%}
%%
foo printf("*FOO*");
bar printf("*BAR*");
foobar printf("*FOOBAR*");
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
string filename = "foo";
FlexLexer* lexer = new yyFlexLexer;
ifstream ifs(filename.c_str());
while(lexer->yylex(&ifs) != 0)
;
return 0;
}
で、
barfoobarfoo
を入力すると、
*BAR**FOOBAR**FOO*
「filename.c_str()」などという回りくどい書き方をする必要などないよう?
!2007-03-25 Sun
%option c++
%{
#include
int yywrap (void);
using namespace std;
%}
%%
foo
bar
foobar
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
lexer->yylex();
//cout << "*" << lexer->yytext << "*" << endl;
cout << "*" << lexer->YYText() << "*" << endl;
return 0;
}
で、
foo
を入力すると、
**
空?
!2007-03-24 Sat
%option c++
%{
int yywrap (void);
%}
%%
foo printf("*FOO*");
bar printf("*BAR*");
foobar printf("*FOOBAR*");
%%
int yywrap (void)
{
return 1;
}
int main(int argc, char *argv)
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
で、
lex.yy.cc が生成される。g++ で -lfl なしでコンパイル
!2007-03-23 Fri
コマンド文パーサ
で、
FIND MEN
QUICKLY FIND MEN
FIND ALL MEN ON THE NETWORK
QUICKLY FIND ALL MEN ON THE NETWORK
FIND ALL MEN ON THE NETWORK QUICKLY
を入力すると(実際には最後は改行を入れない)、
I understand that sentence.
VP = FIND
NP = MEN
PP =
AD =
I understand that sentence.
VP = QUICKLY FIND
NP = MEN
PP =
AD =
I understand that sentence.
VP = FIND
NP = ALL MEN
PP = ON THE NETWORK
AD =
I understand that sentence.
VP = QUICKLY FIND
NP = ALL MEN
PP = ON THE NETWORK
AD =
I understand that sentence.
VP = FIND
NP = ALL MEN
PP = ON THE NETWORK
AD = QUICKLY
「conflicts: 2 shift/reduce」が出ていた
この注↓意味分からない。なくてもコンパイルできたよ
注:Bisonパーサは`alloca.c'というファイルを必要とします。このファイルは
examplesサブディレクトリにあります。 Bisonの代わりにyaccを使うのであれば、
このファイルは必要ありません。
!2007-03-22 Thu
expr.y と expr.lex
で、
1+2*(199*2)
797
1 + 2 * (199*2)
Illegal character
1
syntax error
* 「cc -o expr y.tab.c lex.yy.c alloca.c」でなく、「gcc y.tab.c lex.yy.c -lfl -lm」でコンパイル
* flex でのコンパイルに -I をつけなくても挙動が変わったようには思えなかった
* スペースには未対応じゃないかー
!2007-03-21 Wed
%{
#include
%}
%x STRING
%%
\" ECHO; BEGIN(STRING);
[^\"\n]* ECHO;
\" ECHO; BEGIN(INITIAL);
%NAME { printf("%s",getenv("LOGNAME")); }
%HOST { printf("%s",getenv("HOST")); }
%HOSTTYPE { printf("%s",getenv("HOSTTYPE"));}
%HOME { printf("%s",getenv("HOME")); }
で、
%NAME
%HOST
%HOSTTYPE
%HOME
"%NAME"
を入力すると、
nnakamur
(null)
(null)
/home/nnakamur
"%NAME"
!2007-03-20 Tue
%%
%NAME { printf("%s",getenv("LOGNAME")); }
%HOST { printf("%s",getenv("HOST")); }
%HOSTTYPE { printf("%s",getenv("HOSTTYPE"));}
%HOME { printf("%s",getenv("HOME")); }
%%
で、
%NAME
%HOST
%HOSTTYPE
%HOME
"%NAME"
を入力すると、
nnakamur
(null)
(null)
/home/nnakamur
"nnakamur"
「-ll」というのもあるんだ〜
!2007-03-19 Mon
%%
foo printf("*%d\n", YY_AT_BOL());
^bar printf("+%d\n", YY_AT_BOL());
"\n" printf("-%d\n", YY_AT_BOL());
%%
で、
foo
bar
を入力すると、
*0
-1
+0
-1
!2007-03-18 Sun
%%
foo ECHO;
^bar printf("*BAR*");
"\n" yy_set_bol(0);
%%
で、
foobar
を入力すると、
foobar
(最後改行なし)
%%
foo ECHO;
^bar printf("*BAR*");
%%
で、
foobar
を入力すると、
foo
*BAR*
!2007-03-17 Sat
yy_set_interactive(is_interactive) とばし。意味が分かっていないから。
そもそも「カレント・バッファ」って何?
%%
foo ECHO; yy_set_bol(1);
^bar printf("*BAR*");
%%
で、
foobar
を入力すると、
foo*BAR*
%%
foo ECHO;
^bar printf("*BAR*");
%%
で、
foobar
を入力すると、
foobar
!2007-03-16 Fri
%{
#define YY_BREAK printf("YY_BREAK\n"); break;
%}
%%
foo ECHO;
bar ECHO;
%%
で、
foo
を入力すると、
fooYY_BREAK
YY_BREAK
!2007-03-15 Thu
%{
void open_input_file(void)
{
char *file_name,buffer[1024];
yyin = NULL;
while (yyin == NULL) {
printf("Input file: ");
file_name = fgets(buffer, 1024, stdin);
if (file_name) {
file_name[strlen(file_name)-1] = '\0';
yyin = fopen(file_name, "r");
if (yyin == NULL) {
printf("Unable to open \"%s\"\n", file_name);
}
} else {
printf("stdin\n");
yyin = stdin;
break;
}
}
}
%}
%%
%%
int main(int argc, char *argv[])
{
open_input_file();
yylex();
}
で、
Foo
を入力すると、
Input file: foo
Foo
!2007-03-14 Wed
%{
#define YY_USER_INIT open_input_file()
extern FILE *yyin;
void open_input_file(void)
{
char *file_name,buffer[1024];
yyin = NULL;
while (yyin == NULL) {
printf("Input file: ");
file_name = fgets(buffer, 1024, stdin);
if (file_name) {
file_name[strlen(file_name)-1] = '\0';
yyin = fopen(file_name, "r");
if (yyin == NULL) {
printf("Unable to open \"%s\"\n", file_name);
}
} else {
printf("stdin\n");
yyin = stdin;
break;
}
}
}
%}
%%
で、
Foo
を入力すると、
$ ./a.out
Input file: foo
Foo
!2007-03-13 Tue
BEGIN はもう使っているので、とばし
%{
#include
void user_action(void);
#define YY_USER_ACTION user_action();
%}
%%
.* ECHO;
\n ECHO;
%%
/*
* このユーザ・アクションはすべての文字を
* 単に大文字に変換する
*/
void user_action(void)
{
int loop;
for(loop=0; loop{nday} printf("*1*%s\n", yytext);
{nmonth} BEGIN(MONTH); REJECT;
{nday} printf("*2*%s\n", yytext);
{nyear} BEGIN(YEAR); REJECT;
{nday} printf("*3*%s\n", yytext);
で、
1230
を入力すると、
1*3*23
0
うーん、さっぱり分かっていないので、
入力もどういうのを与えれば良いか分からない…
!2007-03-11 Sun
%%
UNIX {
unput('U'); unput('N');
unput('G'); unput('\0');
REJECT;
}
GNU printf("GNU is Not Unix!\n");
%%
で、
UNIX
を入力すると、
UGNU is Not Unix! ゴミ...
GNU is Not Unix!
なぜゴミが出るのだ???
!2007-03-10 Sat
%%
foo printf("*FOO*"); REJECT
fo. printf("*FO.*");
bar printf("*BAR*");
%%
で、
foofoobarfoo
を入力すると、
*FOO**FO.**FOO**FO.**BAR**FOO**FO.*
%%
foo REJECT; printf("*FOO*");
fo. printf("*FO.*");
bar printf("*BAR*");
%%
で、
foofoobarfoo
を入力すると、
*FO.**FO.**BAR**FO.*
!2007-03-09 Fri
%%
foo REJECT
fo. printf("*FO.*");
bar printf("*BAR*");
%%
で、
foofoobarfoo
を入力すると、
*FO.**FO.**BAR**FO.*
!2007-03-08 Thu
マッチの仕方確認
%%
foo printf("*FOO*");
fo. printf("*FO.*");
bar printf("*BAR*");
%%
で、
foofoobarfoo
を入力すると、
*FOO**FOOBAR**FOO*
%%
fo. printf("*FO.*");
foo printf("*FOO*");
bar printf("*BAR*");
%%
で、
foofoobarfoo
を入力すると、
*FO.**FO.**BAR**FO.*
2行目はマッチしないというワーニングが出ていた
!2007-03-07 Wed
こんなところで ECHO が出てきたよ。もう使っているので、とばし。
ちょっと最長一致を確認
%%
foo printf("*FOO*");
bar printf("*BAR*");
foobar printf("*FOOBAR*");
%%
で、
foofoobarfoo
を入力すると、
*FOO**FOOBAR**FOO*
!2007-03-06 Tue
YY_NEW_FILE の例 cat.lex
で、
$ ./a.out foo foo
foofoobarfoo
foofoobarfoo
!2007-03-05 Mon
%{
#include
%}
%%
foo ECHO;
bar ECHO; yyterminate();
%%
int yywrap (void)
{
return 1;
}
int main(argc,argv)
int argc;
char *argv;
{
printf("*%d*\n", yylex());
yyrestart(yyin);
printf("*%d*\n", yylex());
}
で、
foofoobarfoo
を入力すると、
foofoobar*0*
*0*
うむ。全く分からない…。
!2007-03-04 Sun
%{
#include
%}
%%
foo ECHO;
bar ECHO; yyterminate();
%%
int yywrap (void)
{
return 1;
}
int main(argc,argv)
int argc;
char *argv;
{
printf("*%d*\n", yylex());
printf("*%d*\n", yylex());
}
で、
foofoobarfoo
を入力すると、
foofoobar*0*
foo
*0*
「yyrestart()が呼び出されない限り、 yylex()を呼び出してもすぐに復帰してしまいます」という仕様通り???
「すぐに復帰してしまいます」の意味が良く分からない
!2007-03-03 Sat
%%
foo ECHO;
bar ECHO; yyterminate();
%%
で、
foofoobarfoo
を入力すると、
foofoobar
!2007-03-02 Fri
やってはいけない例
%{
#include
/*#define yytext_ptr yytext*/
void putback_yytext(void);
%}
%%
foobar putback_yytext();
raboof putback_yytext();
%%
#define yytext_ptr yytext
void putback_yytext(void)
{
int i;
int l = strlen(yytext);
char buffer[YY_BUF_SIZE];
strcpy(buffer, yytext);
printf("Got: %s\n",yytext);
for (i = 0; i < l; i++) {
unput(buffer[i]);
}
}
で、
foobar
を入力すると、
Got: foobar
Got: raboof
Got: foobar
Got: raboof
...
無限ループ!
* コードそのままでは yytext_ptr がないとエラーに
!2007-03-01 Thu
%%
foobar {
char *baz = "baz";
int i = strlen(baz) - 1;
while (i >= 0) {
unput(baz[i]);
i--;
}
}
%%
で、
foobar
を入力すると、
baz
!2007-02-28 Wed
%%
foo unput('b');
%%
で、
foo
を入力すると、
b
!2007-02-27 Tue
今度はうまく動く(らしい)例
%%
"/*" {
int a,b;
a = input();
while (a != EOF) {
b = input();
if (a == '*' && b == '/') {
break;
} else {
a = b;
}
}
if (a == EOF) {
/* error_message("EOF in comment"); */
printf("EOF in comment");
}
}
%%
で、
/* comment */
/*
*/
を入力すると、
!2007-02-26 Mon
またまた、うまく処理できない例
%%
"/*"[.\n]*"*/"
%%
で、
/* comment */
/*
*/
を入力すると、
/* comment */
!2007-02-25 Sun
複数行にわたるコメントをうまく処理できない例
%%
"/*".*"*/"
%%
で、
/* comment */
/*
*/
を入力すると、
/*
*/
!2007-02-24 Sat
%%
foobar ECHO; yyless(3);
%%
で、
foobar
を入力すると、
foobarbar
!2007-02-23 Fri
%%
foobar ECHO; yyless(3);
[a-z]+ ECHO;
%%
で、
foobar
を入力すると、
foobarbar
!2007-02-22 Thu
%{
#include
void yyerror(char *message)
{
printf("Error: %s\n",message);
}
%}
%x STRING
%%
\" BEGIN(STRING);