継続は力にゃりん。毎日続けることができるのか? 候補 * 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); [^\\\n"]* yymore(); <> { yyerror("EOF in string."); BEGIN(INITIAL); } \n { yyerror("Unterminated string."); BEGIN(INITIAL); } \\\n yymore(); /* 複数行にわたる * 文字列を処理する */ \" { yytext[yyleng-1] = '\0'; printf("string = \"%s\"",yytext); BEGIN(INITIAL); } %% で、 "foo" "foo \ bar" を入力すると、 string = "foo" string = "foo \ bar" * こんな入力で良いのだろうか?いまいち良く分かっていないのだが… * 「[^\\\n"]* yymore();」の部分は何を?読みとばし? !2007-02-21 Wed %% foo ECHO; yymore(); bar ECHO; %% で、 foobar を入力すると、 foofoobar そもそも ECHO って何よ? !2007-02-20 Tue DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* %% {DIGIT} printf("(%d)", yyleng); {LETTER} printf("<%d>", yyleng); {IDENT} printf("[%d]", yyleng); %% で、 0 a a1 を入力すると、 (1) <1> [2] !2007-02-19 Mon DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* %% {DIGIT} printf("(%s)", yytext); {LETTER} printf("<%s>", yytext); {IDENT} printf("[%s]", yytext); %% で、 0 a a1 を入力すると、 (0) [a1] 「`examples'サブディレクトリ」なんて記述があるので、 ソースにそういうのが含まれているらしい。今度見よ〜 !2007-02-18 Sun %{ #include %} DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* %% {DIGIT} fprintf(yyout, "digit!!"); {LETTER} fprintf(yyout, "letter!!"); {IDENT} fprintf(yyout, "ident!!"); %% int yywrap (void) { return 1; } int main(argc,argv) int argc; char *argv; { yyout = fopen("foo", "w"); yylex(); fclose(yyout); } で、 0 a a1 を入力すると、ファイル foo は digit!! letter!! ident!! !2007-02-17 Sat %{ #include %} DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* %% {DIGIT} printf("digit!!"); {LETTER} printf("letter!!"); {IDENT} printf("ident!!"); %% int yywrap (void) { return 1; } int main(argc,argv) int argc; char *argv; { yyout = fopen("foo", "w"); yylex(); fclose(yyout); } で、 0 a a1 を入力すると、標準出力には、 digit!!letter!!ident!! ファイル foo には、改行が あれ? printf を使っているのがいけないのかな? !2007-02-16 Fri %{ #include #undef YY_INPUT #define YY_INPUT(buffer,result,max_size) \ {\ buffer[0] = getchar();\ if(buffer[0] == EOF)\ result = YY_NULL;\ else\ result = 1;\ } %} DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* %% {DIGIT} printf("digit!!"); {LETTER} printf("letter!!"); {IDENT} printf("ident!!"); %% int yywrap (void) { return 1; } int main(argc,argv) int argc; char *argv; { yylex(); } で、 0 a a1 を入力すると、 digit!! letter!! ident!! !2007-02-15 Thu %{ #include %} DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* %% {DIGIT} printf("digit!!"); {LETTER} printf("letter!!"); {IDENT} printf("ident!!"); %% int yywrap (void) { return 1; } int main(argc,argv) int argc; char *argv; { yyin = fopen("foo", "r"); yylex(); fclose(yyin); } で、 0 a a1 を入力すると、 digit!! letter!! ident!! !2007-02-14 Wed %{ #include #undef YY_DECL #define YY_DECL char *gettok() %} DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* %% {DIGIT} return "DIGIT"; {LETTER} return "LETTER"; {IDENT} return "IDENT"; %% int yywrap(void) { return 1; } int main(int argc, char *argv) { char *return_code; while (return_code = gettok()) { printf("*%s*", return_code); } } で、 0 a a1 を入力すると、 *DIGIT* *LETTER* *IDENT* マニュアルだと「#define YY_DECL char *gettok(char *buffer)」と なっているのだが、buffer は何に使うのだろう? 戻り値に使うのか??? !2007-02-13 Tue %{ #include #define DIGIT 1 #define LETTER 2 #define IDENT 3 %} DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* %% {DIGIT} return DIGIT; {LETTER} return LETTER; {IDENT} return IDENT; %% int yywrap(void) { return 1; } int main(int argc, char *argv) { int return_code; while ((return_code = yylex()) != 0) { switch (return_code) { case DIGIT: printf("*DIGIT*"); break; default: printf("*%d*", return_code); } } } で、 0 a a1 を入力すると、 *DIGIT* *2* *3* !2007-02-12 Mon -lfl なしでコンパイル %{ #include %} DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* ALPHANUM {LETTER}|{DIGIT} %% {LETTER} printf("letter!!\n"); %% int yywrap (void) { return 1; } int main(argc,argv) int argc; char *argv; { yylex(); } で、 0 a a1 を入力すると、 0 letter!! letter!! 1 !2007-02-11 Sun 「スタート状態の使用例」のコード dates.lex で、 short 1989:12:23 1989:11:12 23:12:1989 11:12:1989 1989/12/23 1989/11/12 23/12/1989 11/12/1989 1989-12-23 1989-11-12 23-12-1989 11-12-1989 long Friday the 5th of January, 1989 Friday, 5th of January, 1989 Friday, January 5th, 1989 Fri, January 5th, 1989 Fri, Jan 5th, 1989 Fri, Jan 5, 1989 FriJan 5, 1989 FriJan5, 1989 FriJan51989 Jan51989 を入力すると、 Short: Day : 23 Month : 12 Year : 1989 Short: Day : 12 Month : 11 Year : 1989 Short: Day : 23 Month : 12 Year : 1989 Short: Day : 11 Month : 12 Year : 1989 Short: Day : 23 Month : 12 Year : 1989 Short: Day : 12 Month : 11 Year : 1989 Short: Day : 23 Month : 12 Year : 1989 Short: Day : 11 Month : 12 Year : 1989 Short: Day : 23 Month : 12 Year : 1989 Short: Day : 12 Month : 11 Year : 1989 Short: Day : 23 Month : 12 Year : 1989 Short: Day : 11 Month : 12 Year : 1989 Long: DOW : Friday Day : 5th Month : January Year : 1989 Long: DOW : Friday Day : 5th Month : January Year : 1989 Long: DOW : Friday Day : 5th Month : January Year : 1989 Long: DOW : Fri Day : 5th Month : January Year : 1989 Long: DOW : Fri Day : 5th Month : Jan Year : 1989 Long: DOW : Fri Day : 5 Month : Jan Year : 1989 Long: DOW : Fri Day : 5 Month : Jan Year : 1989 Long: DOW : Fri Day : 5 Month : Jan Year : 1989 Long: DOW : Fri Day : 5 Month : Jan Year : 1989 Long: DOW : Day : 5 Month : Jan Year : 1989 ルールの後にコメントがあると flex がエラーに !2007-02-10 Sat %{ #define MAX_STATES 10 int last_state[MAX_STATES]; int state_count = 0; %} %option stack %x FOO BAR baz %% FOO { /*printf("init:%d\n", yy_top_state());*/ printf("foo1:%d\n", YY_START); yy_push_state(baz); printf("foo2:%d\n", YY_START); printf("init:%d\n", yy_top_state()); } BAR { printf("bar1:%d\n", YY_START); yy_push_state(baz); printf("bar2:%d\n", YY_START); } END { printf("end1:%d\n", YY_START); yy_pop_state(); printf("end2:%d\n", YY_START); } で、 FOO END BAR END を入力すると、 foo1:0 foo2:3 init:0 end1:3 end2:0 bar1:0 bar2:3 end1:3 end2:0 !2007-02-09 Fri %{ #define MAX_STATES 10 int last_state[MAX_STATES]; int state_count = 0; %} %option stack %x FOO BAR baz %% FOO { yy_push_state(baz); printf("foo:%d\n", YY_START); } BAR { yy_push_state(baz); printf("bar:%d\n", YY_START); } END { printf("end:%d\n", YY_START); yy_pop_state(); } で、 FOO FOO BAR END END を入力すると、 foo1:0 foo2:3 end1:3 end2:0 bar1:0 bar2:3 end1:3 end2:0 !2007-02-08 Thu %x COMMENT %% "{" BEGIN(COMMENT); { "$R" "$I" "$M" "}" BEGIN(INITIAL); } %% で、 {$I-} を入力すると、 - !2007-02-07 Wed 互換性のために YYSTATE も使える %{ #define MAX_STATES 10 int last_state[MAX_STATES]; int state_count = 0; %} %x FOO BAR baz %% FOO { last_state[state_count] = YYSTATE; printf("foo:%d\n", YYSTATE); state_count++; BEGIN(baz); } BAR { last_state[state_count] = YYSTATE; printf("bar:%d\n", YYSTATE); state_count++; BEGIN(baz); } END { printf("end:%d\n", YYSTATE); state_count--; BEGIN(last_state[state_count]); } !2007-02-06 Tue %{ #define MAX_STATES 10 int last_state[MAX_STATES]; int state_count = 0; %} %x FOO BAR baz %% FOO { last_state[state_count] = YY_START; printf("foo:%d\n", YY_START); state_count++; BEGIN(baz); } BAR { last_state[state_count] = YY_START; printf("bar:%d\n", YY_START); state_count++; BEGIN(baz); } END { printf("end:%d\n", YY_START); state_count--; BEGIN(last_state[state_count]); } で、 FOO END BAR END を入力すると、 foo:0 end:3 bar:0 end:3 !2007-02-05 Mon %x state1 %% 1 BEGIN(state1); "one" printf("two"); <*>"three" printf("four"); で、 one three 1 one three を入力すると、 one four two four !2007-02-04 Sun %{ #define MAX_STATES 10 int last_state[MAX_STATES]; int state_count = 0; %} %x FOO BAR baz %% FOO { last_state[state_count] = FOO; state_count++; BEGIN(baz); } BAR { last_state[state_count] = BAR; state_count++; BEGIN(baz); } END { state_count--; BEGIN(last_state[state_count]); } で、 FOO FOO BAR END END を入力すると、 FOO BAR END * 「int last_state[MAX_STATES]」で最後の「;」が抜けていた * 「statecount--;」「BEGIN(last_state[statecount]);」でなく、それぞれ「state_count--;」「BEGIN(last_state[state_count]);」が正しい !2007-02-03 Sat %x PASCAL %x C %% begin return(OPEN_BLOCK); end return(CLOSE_BLOCK); "{" return(OPEN_BLOCK); "}" return(CLOSE_BLOCK); 「{」「}」だとエラーに。 !2007-02-02 Fri %x state1 %s state2 %% 1 BEGIN(state1); 2 BEGIN(state2); "something" printf("SOMETHING"); "another thing" printf("ANOTHER THING"); "something else" printf("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-02-01 Thu 「スタート状態に関する注意」 %x state1 %s state2 %% "something" "another thing" "something else" で * 「 "something"」のように状態と文字列の間にスペースがあると怒られてしまった * 「 "something else"」は「"something else"」の間違い。state -> state1。スペースがあるとダメ(2箇所) !2007-01-31 Wed BEGIN は最初でなくても良いか? %x state1 %% "one" printf("two"); "three" printf("four"); @ BEGIN(state1); %% で、 three @one three を入力すると、 four two three !2007-01-30 Tue Pascal のコメント %x COMMENT %% "{" BEGIN(COMMENT); "$R" "$I" "$M" "}" BEGIN(INITIAL); %% で、 {$I-} を入力すると、 - !2007-01-29 Mon INITIAL 状態 %x state1 %% @ BEGIN(state1); "one" printf("two"); "three" printf("four"); - BEGIN(INITIAL); %% で、 three @one three -three を入力すると、 four two three four !2007-01-28 Sun 排他的スタート状態(%x) %x state1 %% @ BEGIN(state1); "one" printf("two"); "three" printf("four"); %% で、 three @one three を入力すると、 four two three !2007-01-27 Sat 包含的スタート状態(%s) %s state1 %% @ BEGIN(state1); "one" printf("two"); "three" printf("four"); %% で、 three @one three を入力すると、 four two four !2007-01-26 Fri %x state1 %s state2 %x state3 state4 %% "foo" "bar" %% !2007-01-25 Thu %% [[:alpha:][:digit:]] printf("ALNUM\n"); %% で、 A1 _ を入力すると、 ALNUM ALNUM _ !2007-01-24 Wed %% [[:xdigit:]] printf("XDIGIT\n"); %% で、 Aa1xXFG を入力すると、 XDIGIT XDIGIT XDIGIT xXXDIGIT G !2007-01-23 Tue %% [[:punct:]] printf("PUNCT\n"); %% で、 Aa1 _. を入力すると、 Aa1 PUNCT PUNCT !2007-01-22 Mon %% [[:print:]] printf("PRINT\n"); %% で、 Aa1 _ を入力すると、 PRINT PRINT PRINT PRINT PRINT !2007-01-21 Sun %% [[:graph:]] printf("GRAPH\n"); %% で、 Aa1 _ を入力すると、 GRAPH GRAPH GRAPH GRAPH !2007-01-20 Sat %% [[:digit:]] printf("DIGIT\n"); [[:space:]] printf("SPACE\n"); [[:lower:]] printf("LOWER\n"); [[:upper:]] printf("UPPER\n"); %% で、 Aa1 _ を入力すると、 UPPER LOWER DIGIT SPACE _SPACE !2007-01-19 Fri %% [[:alnum:]] printf("ALNUM\n"); [[:blank:]] printf("BLANK\n"); [[:cntrl:]] printf("CNTRL\n"); %% で、 a1 _ を入力すると、 ALNUM ALNUM BLANK _CNTRL !2007-01-18 Thu %% [[:alpha:]] printf("ALPHA\n"); %% で、 a1_ を入力すると、 ALPHA 1_ !2007-01-17 Wed %% [[:alnum:]] printf("ALNUM\n"); %% で、 a1_ を入力すると、 ALNUM ALNUM _ !2007-01-16 Tue %% [:alnum:] printf("ALNUM\n"); %% で、 a1_ を入力すると、 ALNUM 1_ 何が起きている? !2007-01-15 Mon string printf("STRING1\n"); "STRING" printf("STRING2\n"); \"string\" printf("STRING3\n"); で、 string STRING "string" を入力すると、 STRING1 STRING2 STRING3 !2007-01-14 Sun %% (^foo|bar) printf("FOO\n"); %% で、 foobar を入力すると、 fooFOO 「()」内に「^」とかは書けないらしい。 というか、特殊文字としては扱われないということらしい。 ^foo を入力すると、 FOO !2007-01-13 Sat %% ^(foo|bar) printf("FOO\n"); %% で、 foobar を入力すると、 FOO bar !2007-01-12 Fri %% (foo|bar) printf("FOO\n"); %% で、 foobar を入力すると、 FOO FOO !2007-01-11 Thu %% end/\n printf("END\n"); %% で、 end endless を入力すると、 END endless !2007-01-10 Wed %% end$ printf("END\n"); %% で、 end endless を入力すると、 END endless !2007-01-09 Tue %% abcdef printf("abcdef\n"); abc/DEF printf("abcDEF\n"); /* error */ abc/def/hijkl printf("abc/def/hijkl\n"); %% 「/」は複数書けない !2007-01-08 Mon %% abcdef printf("abcdef\n"); abc/DEF printf("abcDEF\n"); %% で、 abcdef abcDEF abc を入力すると、 abcdef abcDEF DEF abc !2007-01-07 Sun %% "string" printf("str\n"); "str ing" printf("STR ING\n"); %% で、 string str ing を入力すると、 str STR ING !2007-01-06 Sat %% f{4,7} printf("f{4,7}\n"); f{3,} printf("f{3,}\n"); f{2} printf("f{2}\n"); %% で、 f ff fff ffff fffff ffffff fffffff ffffffff を入力すると、 f f{2} f{3,} f{4,7} f{4,7} f{4,7} f{4,7} f{3,} !2007-01-05 Fri %% [a-z] printf("a-z"); ^foo printf("^foo"); foo^ printf("foo^"); . printf("."); %% で、 a foo afoo foo^ hoge . A を入力すると、 a-z ^foo a-za-za-za-z foo^ a-za-za-za-z . . !2007-01-04 Thu %% foobar %% で、 foobar hoge を入力すると、 hoge !2007-01-03 Wed %% hi | bonjour | hello printf("hello\n"); goodbye { printf("goodbye!\n"); } konnichiwa { printf("konnichiwa"); printf(" oha!\n"); } sayonara printf("lex will not"); printf("print this"); %% で、 hi bonjour hello goodbye konnichiwa sayonara hiyo を入力すると、 hello hello hello goodbye! konnichiwa oha! lex will notprint this hello yo !2007-01-02 Tue FUNCTION ^[a-zA-Z_][a-zA-Z0-9_]*"(" %% {FUNCTION} printf("got a function\n"); %% で、 int foo( bar を入力すると、 int foo( bar ダメな例らしいので、、、 (良い書き方はいまのところ不明) !2007-01-01 Mon DIGIT [0-9] LETTER [a-z] IDENT [a-z_][a-z0-9]* ALPHANUM {LETTER}|{DIGIT} %% {LETTER} printf("letter!!\n"); %% で、 0 a a1 を入力すると、 0 letter!! letter!! 1 こんなもんなんだっけ?