From 7a8b3f9c432506a3f764232173781b311d246492 Mon Sep 17 00:00:00 2001 From: pjht Date: Sun, 23 Jun 2019 10:40:25 -0500 Subject: [PATCH] Commit current state --- Gemfile | 1 + Gemfile.lock | 2 + Rakefile | 7 + compiler | 196 +++++++++++++++++ lexer.rb | 205 ++++++++++++++++++ lexer.rex | 56 +++++ main.c | 5 + out | Bin 0 -> 4248 bytes out.asm | 20 ++ parser.rb | 593 +++++++++++++++++++++++++++++++++++++++++++++++++++ parser.y | 64 ++++++ 11 files changed, 1149 insertions(+) create mode 100644 Rakefile create mode 100755 compiler create mode 100644 lexer.rb create mode 100644 lexer.rex create mode 100644 main.c create mode 100755 out create mode 100644 out.asm create mode 100644 parser.rb create mode 100644 parser.y diff --git a/Gemfile b/Gemfile index 7ab0ba3..1b503b6 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,4 @@ source "https://rubygems.org" gem "rexical" gem "racc" +gem "rake" diff --git a/Gemfile.lock b/Gemfile.lock index 2421a99..31cb4d4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,6 +2,7 @@ GEM remote: https://rubygems.org/ specs: racc (1.4.14) + rake (12.3.2) rexical (1.0.5) PLATFORMS @@ -9,6 +10,7 @@ PLATFORMS DEPENDENCIES racc + rake rexical BUNDLED WITH diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..2b9c5d3 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +task :default => ["lexer.rb","parser.rb"] +file "lexer.rb" => ["lexer.rex"] do + `rex lexer.rex -o lexer.rb` +end +file "parser.rb" => ["parser.y"] do + `racc parser.y -o parser.rb` +end diff --git a/compiler b/compiler new file mode 100755 index 0000000..c97088e --- /dev/null +++ b/compiler @@ -0,0 +1,196 @@ +#! /usr/bin/env ruby +`rake` +require "./parser.rb" +$indx_map=-8 +$var_map={} +$tab_level=-1 +def generate_expr(expression) + $tab_level+=1 + $tab_level.times do + print "-" + end + code="" + p expression + case expression[:type] + when :number + code+="mov rax,#{expression[:value]}\n" + when :neg + code+=generate_expr(expression[:expr]) + code+="neg rax\n" + when :comp + code+=generate_expr(expression[:expr]) + code+="not rax\n" + when :lneg + code+=generate_expr(expression[:expr]) + code+="cmp rax,0\n" + code+="mov rax,0\n" + code+="sete al\n" + when :var + code+="mov rax,[rbp#{$var_map[expression[:name]][1]}]\n" + when :assign + code+=generate_expr(expression[:expr]) + code+="mov [rbp#{$var_map[expression[:name]][1]}],rax\n" + when :comma + code+=generate_expr(expression[:expr1]) + code+=generate_expr(expression[:expr2]) + when :seteq + expression[:type]=expression[:op] + name=expression[:name] + expression.delete :op + expression.delete :name + code+=generate_expr({:type=>:assign,:name=>name,:expr=>expression}) + else + code+=generate_expr(expression[:expr1]) + code+="push rax\n" + code+=generate_expr(expression[:expr2]) + code+="pop rcx\n" + case expression[:type] + when :plus + code+="add rax,rcx\n" + when :minus + code+="push rax\n" + code+="push rcx\n" + code+="pop rax\n" + code+="pop rcx\n" + code+="sub rax,rcx\n" + when :mul + code+="imul rax,rcx\n" + when :div + code+="push rax\n" + code+="push rcx\n" + code+="pop rax\n" + code+="pop rcx\n" + code+="mov edx,0\n" + code+="idiv ecx\n" + when :mod + code+="push rax\n" + code+="push rcx\n" + code+="pop rax\n" + code+="pop rcx\n" + code+="mov edx,0\n" + code+="idiv ecx\n" + code+="mov eax,edx\n" + when :eq + code+="cmp rax,rcx\n" + code+="mov rax,0\n" + code+="sete al\n" + when :ne + code+="cmp rax,rcx\n" + code+="mov rax,0\n" + code+="setne al\n" + when :ge + code+="cmp rax,rcx\n" + code+="mov rax,0\n" + code+="setge al\n" + when :le + code+="cmp rax,rcx\n" + code+="mov rax,0\n" + code+="setle al\n" + when :gt + code+="cmp rax,rcx\n" + code+="mov rax,0\n" + code+="setgt al\n" + when :lt + code+="cmp rax,rcx\n" + code+="mov rax,0\n" + code+="setlt al\n" + when :lor + code+="or eax,ecx\n" + code+="mov eax,0\n" + code+="setne al\n" + when :land + code+="cmp ecx,0\n" + code+="setne cl\n" + code+="cmp eax,0\n" + code+="mov eax,0\n" + code+="setne al\n" + code+="and al,cl\n" + when :shl + code+="push rax\n" + code+="push rcx\n" + code+="pop rax\n" + code+="pop rcx\n" + code+="shl rax,cl\n" + when :shr + code+="push rax\n" + code+="push rcx\n" + code+="pop rax\n" + code+="pop rcx\n" + code+="shr rax,cl\n" + when :and + code+="and rax,rcx\n" + when :or + code+="or rax,rcx\n" + when :xor + code+="xor rax,rcx\n" + end + end + $tab_level-=1 + return code +end +def generate_statement(statement) + $tab_level+=1 + $tab_level.times do + print "-" + end + p statement + code="" + case statement[:type] + when :return + code+=generate_expr(statement[:expr]) + code+="mov rsp,rbp\n" + code+="pop rbp\n" + code+="ret\n" + when :vardecl + code+="push 0\n" + $var_map[statement[:varname]]=[statement[:vartype],$indx] + $indx-=8 + when :vardeclinit + code+=generate_expr(statement[:init]) + code+="push rax\n" + $var_map[statement[:varname]]=[statement[:vartype],$indx] + $indx-=8 + when :expr + code+=generate_expr(statement[:expr]) + end + $tab_level-=1; + return code +end +def generate_block(block) + code="" + for statement in block + code+=generate_statement(statement) + end + return code +end +def generate_func(func) + code="" + $indx=-8 + $var_map={} + code+=".globl _#{func[:name]}\n" + code+="_#{func[:name]}:\n" + code+="push rbp\n" + code+="mov rbp,rsp\n" + code+=generate_block(func[:code]) + code+="mov rax,0\n" + code+="mov rsp,rbp\n" + code+="pop rbp\n" + code+="ret\n" + return code +end +def generate(ast) + code="" + for func in ast + code+=generate_func(func) + end + return code +end +program=File.read("main.c") +p CX86.new.tokenize(program) +ast=CX86.new.parse(program) +code=generate(ast) +#puts code +f=File.open("out.asm","w") +f.puts code +f.close +puts `gcc -masm=intel -o out out.asm;./out;echo $?` diff --git a/lexer.rb b/lexer.rb new file mode 100644 index 0000000..fe7e4c1 --- /dev/null +++ b/lexer.rb @@ -0,0 +1,205 @@ +#-- +# DO NOT MODIFY!!!! +# This file is automatically generated by rex 1.0.5 +# from lexical definition file "lexer.rex". +#++ + +require 'racc/parser' +class CX86 < Racc::Parser + require 'strscan' + + class ScanError < StandardError ; end + + attr_reader :lineno + attr_reader :filename + attr_accessor :state + + def scan_setup(str) + @ss = StringScanner.new(str) + @lineno = 1 + @state = nil + end + + def action + yield + end + + def scan_str(str) + scan_setup(str) + do_parse + end + alias :scan :scan_str + + def load_file( filename ) + @filename = filename + open(filename, "r") do |f| + scan_setup(f.read) + end + end + + def scan_file( filename ) + load_file(filename) + do_parse + end + + + def next_token + return if @ss.eos? + + # skips empty actions + until token = _next_token or @ss.eos?; end + token + end + + def _next_token + text = @ss.peek(1) + @lineno += 1 if text == "\n" + token = case @state + when nil + case + when (text = @ss.scan(/int/)) + action {[:TYPE,:INT]} + + when (text = @ss.scan(/\(/)) + action {[:OPEN_PAREN,"("]} + + when (text = @ss.scan(/\)/)) + action {[:CLOSE_PAREN,")"]} + + when (text = @ss.scan(/\{/)) + action {[:OPEN_CURLY,"{"]} + + when (text = @ss.scan(/\}/)) + action {[:CLOSE_CURLY,"}"]} + + when (text = @ss.scan(/;/)) + action {[:SEMICOLON,";"]} + + when (text = @ss.scan(/-/)) + action {[:MINUS,"-"]} + + when (text = @ss.scan(/~/)) + action {[:COMP,"~"]} + + when (text = @ss.scan(/!/)) + action {[:LNEG,"!"]} + + when (text = @ss.scan(/\+=/)) + action {[:SETEQ,:plus]} + + when (text = @ss.scan(/\-\=/)) + action {[:SETEQ,:minus]} + + when (text = @ss.scan(/\/\=/)) + action {[:SETEQ,:mul]} + + when (text = @ss.scan(/\*\=/)) + action {[:SETEQ,:div]} + + when (text = @ss.scan(/\%\=/)) + action {[:SETEQ,:mod]} + + when (text = @ss.scan(/\<\<\=/)) + action {[:SETEQ,:shl]} + + when (text = @ss.scan(/\>\>\=/)) + action {[:SETEQ,:shr]} + + when (text = @ss.scan(/\&\=/)) + action {[:SETEQ,:and]} + + when (text = @ss.scan(/\|\=/)) + action {[:SETEQ,:or]} + + when (text = @ss.scan(/\^\=/)) + action {[:SETEQ,:xor]} + + when (text = @ss.scan(/\+/)) + action {[:PLUS,"+"]} + + when (text = @ss.scan(/\*/)) + action {[:MUL,"*"]} + + when (text = @ss.scan(/\//)) + action {[:DIV,"/"]} + + when (text = @ss.scan(/%/)) + action {[:MOD,"%"]} + + when (text = @ss.scan(/\&/)) + action {[:AND,"&"]} + + when (text = @ss.scan(/\|/)) + action {[:OR,"|"]} + + when (text = @ss.scan(/\^/)) + action {[:XOR,"^"]} + + when (text = @ss.scan(/<>/)) + action {[:SHR,">>"]} + + when (text = @ss.scan(/\&\&/)) + action {[:LAND,"&&"]} + + when (text = @ss.scan(/\|\|/)) + action {[:LOR,"||"]} + + when (text = @ss.scan(/\=\=/)) + action {[:EQ,"=="]} + + when (text = @ss.scan(/\!\=/)) + action {[:NE,"!="]} + + when (text = @ss.scan(/\/)) + action {[:GT,">"]} + + when (text = @ss.scan(/\>\=/)) + action {[:GE,">="]} + + when (text = @ss.scan(/=/)) + action {[:EQUALS,"="]} + + when (text = @ss.scan(/,/)) + action {[:COMMA,","]} + + when (text = @ss.scan(/return/)) + action {[:RETURN,"return"]} + + when (text = @ss.scan(/\d+/)) + action {[:NUM,text.to_i]} + + when (text = @ss.scan(/\w+/)) + action {[:IDENT,text]} + + when (text = @ss.scan(/[ \t\n]+/)) + action {} + + else + text = @ss.string[@ss.pos .. -1] + raise ScanError, "can not match: '" + text + "'" + end # if + + else + raise ScanError, "undefined state: '" + state.to_s + "'" + end # case state + token + end # def _next_token + +def tokenize(code) + scan_setup(code) + tokens = [] + while token = next_token + tokens << token + end + tokens +end # class +end diff --git a/lexer.rex b/lexer.rex new file mode 100644 index 0000000..22ce502 --- /dev/null +++ b/lexer.rex @@ -0,0 +1,56 @@ +class CX86 +macro +BLANK [\ \t\n]+ +rule +int {[:TYPE,:INT]} +\( {[:OPEN_PAREN,"("]} +\) {[:CLOSE_PAREN,")"]} +\{ {[:OPEN_CURLY,"{"]} +\} {[:CLOSE_CURLY,"}"]} +; {[:SEMICOLON,";"]} +- {[:MINUS,"-"]} +~ {[:COMP,"~"]} +! {[:LNEG,"!"]} +\+= {[:SETEQ,:plus]} +\-\= {[:SETEQ,:minus]} +\/\= {[:SETEQ,:mul]} +\*\= {[:SETEQ,:div]} +\%\= {[:SETEQ,:mod]} +\<\<\= {[:SETEQ,:shl]} +\>\>\= {[:SETEQ,:shr]} +\&\= {[:SETEQ,:and]} +\|\= {[:SETEQ,:or]} +\^\= {[:SETEQ,:xor]} +\+ {[:PLUS,"+"]} +\* {[:MUL,"*"]} +\/ {[:DIV,"/"]} +% {[:MOD,"%"]} +\& {[:AND,"&"]} +\| {[:OR,"|"]} +\^ {[:XOR,"^"]} +<< {[:SHL,"<<"]} +>> {[:SHR,">>"]} +\&\& {[:LAND,"&&"]} +\|\| {[:LOR,"||"]} +\=\= {[:EQ,"=="]} +\!\= {[:NE,"!="]} +\< {[:LT,"<"]} +\<\= {[:LE,"<="]} +\> {[:GT,">"]} +\>\= {[:GE,">="]} += {[:EQUALS,"="]} +, {[:COMMA,","]} +return {[:RETURN,"return"]} +\d+ {[:NUM,text.to_i]} +\w+ {[:IDENT,text]} +{BLANK} {} +inner +def tokenize(code) + scan_setup(code) + tokens = [] + while token = next_token + tokens << token + end + tokens +end +end diff --git a/main.c b/main.c new file mode 100644 index 0000000..38cab4e --- /dev/null +++ b/main.c @@ -0,0 +1,5 @@ +int main() { + int x=2; + x+=2; + return x; +} diff --git a/out b/out new file mode 100755 index 0000000000000000000000000000000000000000..6721483dc414935416c65732ddcfab5056130da2 GIT binary patch literal 4248 zcmeHKJxd%>6usjIN@8@Ypd^qrsHlj$MTBh=GB^@3OZ-3udAQjLJK%0$cUIRds zzu|n6G(3?$zyXxXznrv}?RRe()y>lBos4;o0j1{b#X0>*@P0~m~Q^ z^Z9?Ifi56ZuT?W^ULjN5Tq}apo&fCQ@Nf3>{!I4b+rrne_0(W>05P;A^5{W;(U>y^ z8^(S4-p%jDIyr!Q>{;Zfjh$cBM*Z2%n(vm!UyY*=uMixPAuOzy#iJAJNW`g+F{6M{ zz$jo8FbWt2i~>dhqkvJsDDa;Yn0K0goZX+CZt~8KeVUKRl4I>TP5YEFr+KpS3vsp> z_?+FIlEIQIvv7ubftC0HpGKc^VHaknRC4mO6z1y|RW2#F;l8i?t}3~!MYk&b 0, + :error => 1, + :TYPE => 2, + :IDENT => 3, + :OPEN_PAREN => 4, + :CLOSE_PAREN => 5, + :OPEN_CURLY => 6, + :CLOSE_CURLY => 7, + :RETURN => 8, + :SEMICOLON => 9, + :EQUALS => 10, + :NUM => 11, + :MINUS => 12, + :COMP => 13, + :LNEG => 14, + :MUL => 15, + :DIV => 16, + :MOD => 17, + :PLUS => 18, + :SHL => 19, + :SHR => 20, + :LT => 21, + :GT => 22, + :LE => 23, + :GE => 24, + :NE => 25, + :EQ => 26, + :AND => 27, + :XOR => 28, + :OR => 29, + :LAND => 30, + :exp => 31, + :LOR => 32, + :SETEQ => 33, + :COMMA => 34 } + +racc_nt_base = 35 + +racc_use_result_var = true + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ + "$end", + "error", + "TYPE", + "IDENT", + "OPEN_PAREN", + "CLOSE_PAREN", + "OPEN_CURLY", + "CLOSE_CURLY", + "RETURN", + "SEMICOLON", + "EQUALS", + "NUM", + "MINUS", + "COMP", + "LNEG", + "MUL", + "DIV", + "MOD", + "PLUS", + "SHL", + "SHR", + "LT", + "GT", + "LE", + "GE", + "NE", + "EQ", + "AND", + "XOR", + "OR", + "LAND", + "exp", + "LOR", + "SETEQ", + "COMMA", + "$start", + "program", + "function", + "block", + "statements", + "statement", + "expression", + "factor", + "term", + "additivexp", + "shiftexp", + "relationalexp", + "equalityexp", + "andexp", + "xorexp", + "orexp", + "landexp", + "lorexp", + "assignexp" ] + +Racc_debug_parser = false + +##### State transition tables end ##### + +# reduce 0 omitted + +module_eval(<<'.,.,', 'parser.y', 2) + def _reduce_1(val, _values, result) + result=[val[0]] + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 3) + def _reduce_2(val, _values, result) + result=[val[0],val[1]].flatten + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 4) + def _reduce_3(val, _values, result) + result={:type=>val[0],:name=>val[1],:code=>val[4]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 5) + def _reduce_4(val, _values, result) + result=val[1] + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 6) + def _reduce_5(val, _values, result) + result=[val[0]] + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 7) + def _reduce_6(val, _values, result) + result=[val[0],val[1]].flatten + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 8) + def _reduce_7(val, _values, result) + result={:type=>:return,:expr=>val[1]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 9) + def _reduce_8(val, _values, result) + result={:type=>:vardecl,:vartype=>val[0],:varname=>val[1]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 10) + def _reduce_9(val, _values, result) + result={:type=>:vardeclinit,:vartype=>val[0],:varname=>val[1],:init=>val[3]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 11) + def _reduce_10(val, _values, result) + result={:type=>:expr,:expr=>val[0]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 12) + def _reduce_11(val, _values, result) + result={:type=>:number,:value=>val[0]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 13) + def _reduce_12(val, _values, result) + result={:type=>:neg,:expr=>val[1]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 14) + def _reduce_13(val, _values, result) + result={:type=>:comp,:expr=>val[1]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 15) + def _reduce_14(val, _values, result) + result={:type=>:lneg,:expr=>val[1]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 16) + def _reduce_15(val, _values, result) + result=val[1] + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 17) + def _reduce_16(val, _values, result) + result={:type=>:var,:name=>val[0]} + result + end +.,., + +# reduce 17 omitted + +module_eval(<<'.,.,', 'parser.y', 19) + def _reduce_18(val, _values, result) + result={:type=>:mul,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 20) + def _reduce_19(val, _values, result) + result={:type=>:div,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 21) + def _reduce_20(val, _values, result) + result={:type=>:mod,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 21 omitted + +module_eval(<<'.,.,', 'parser.y', 23) + def _reduce_22(val, _values, result) + result={:type=>:plus,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 24) + def _reduce_23(val, _values, result) + result={:type=>:minus,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 24 omitted + +module_eval(<<'.,.,', 'parser.y', 26) + def _reduce_25(val, _values, result) + result={:type=>:shl,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 27) + def _reduce_26(val, _values, result) + result={:type=>:shr,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 27 omitted + +module_eval(<<'.,.,', 'parser.y', 29) + def _reduce_28(val, _values, result) + result={:type=>:lt,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 30) + def _reduce_29(val, _values, result) + result={:type=>:gt,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 31) + def _reduce_30(val, _values, result) + result={:type=>:le,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 32) + def _reduce_31(val, _values, result) + result={:type=>:ge,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 32 omitted + +module_eval(<<'.,.,', 'parser.y', 34) + def _reduce_33(val, _values, result) + result={:type=>:ne,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 35) + def _reduce_34(val, _values, result) + result={:type=>:eq,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 35 omitted + +module_eval(<<'.,.,', 'parser.y', 37) + def _reduce_36(val, _values, result) + result={:type=>:and,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 37 omitted + +module_eval(<<'.,.,', 'parser.y', 39) + def _reduce_38(val, _values, result) + result={:type=>:xor,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 39 omitted + +module_eval(<<'.,.,', 'parser.y', 41) + def _reduce_40(val, _values, result) + result={:type=>:or,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 41 omitted + +module_eval(<<'.,.,', 'parser.y', 43) + def _reduce_42(val, _values, result) + result={:type=>:land,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 43 omitted + +module_eval(<<'.,.,', 'parser.y', 45) + def _reduce_44(val, _values, result) + result={:type=>:lor,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +# reduce 45 omitted + +module_eval(<<'.,.,', 'parser.y', 47) + def _reduce_46(val, _values, result) + result={:type=>:assign,:name=>val[0],:expr=>val[2]} + result + end +.,., + +module_eval(<<'.,.,', 'parser.y', 48) + def _reduce_47(val, _values, result) + result={:type=>:assign,:name=>val[0],:expr=>{:type=>val[1],:expr1=>{:type=>:var,:name=>val[0]},:expr2=>val[2]}} + result + end +.,., + +# reduce 48 omitted + +module_eval(<<'.,.,', 'parser.y', 50) + def _reduce_49(val, _values, result) + result={:type=>:comma,:expr1=>val[0],:expr2=>val[2]} + result + end +.,., + +def _reduce_none(val, _values, result) + val[0] +end + +end # class CX86 diff --git a/parser.y b/parser.y new file mode 100644 index 0000000..c42840c --- /dev/null +++ b/parser.y @@ -0,0 +1,64 @@ +class CX86 +rule + program: function {result=[val[0]]} + | function program {result=[val[0],val[1]].flatten} + function: TYPE IDENT OPEN_PAREN CLOSE_PAREN block {result={:type=>val[0],:name=>val[1],:code=>val[4]}} + block: OPEN_CURLY statements CLOSE_CURLY {result=val[1]} + statements: statement {result=[val[0]]} + | statement statements {result=[val[0],val[1]].flatten} + statement: RETURN expression SEMICOLON {result={:type=>:return,:expr=>val[1]}} + | TYPE IDENT SEMICOLON {result={:type=>:vardecl,:vartype=>val[0],:varname=>val[1]}} + | TYPE IDENT EQUALS expression SEMICOLON {result={:type=>:vardeclinit,:vartype=>val[0],:varname=>val[1],:init=>val[3]}} + | expression SEMICOLON {result={:type=>:expr,:expr=>val[0]}} + factor: NUM {result={:type=>:number,:value=>val[0]}} + | MINUS factor {result={:type=>:neg,:expr=>val[1]}} + | COMP factor {result={:type=>:comp,:expr=>val[1]}} + | LNEG factor {result={:type=>:lneg,:expr=>val[1]}} + | OPEN_PAREN expression CLOSE_PAREN {result=val[1]} + | IDENT {result={:type=>:var,:name=>val[0]}} + term: factor + | term MUL factor {result={:type=>:mul,:expr1=>val[0],:expr2=>val[2]}} + | term DIV factor {result={:type=>:div,:expr1=>val[0],:expr2=>val[2]}} + | term MOD factor {result={:type=>:mod,:expr1=>val[0],:expr2=>val[2]}} + additivexp: term + | additivexp PLUS term {result={:type=>:plus,:expr1=>val[0],:expr2=>val[2]}} + | additivexp MINUS term {result={:type=>:minus,:expr1=>val[0],:expr2=>val[2]}} + shiftexp: additivexp + | shiftexp SHL additivexp {result={:type=>:shl,:expr1=>val[0],:expr2=>val[2]}} + | shiftexp SHR additivexp {result={:type=>:shr,:expr1=>val[0],:expr2=>val[2]}} + relationalexp: shiftexp + | relationalexp LT shiftexp {result={:type=>:lt,:expr1=>val[0],:expr2=>val[2]}} + | relationalexp GT shiftexp {result={:type=>:gt,:expr1=>val[0],:expr2=>val[2]}} + | relationalexp LE shiftexp {result={:type=>:le,:expr1=>val[0],:expr2=>val[2]}} + | relationalexp GE shiftexp {result={:type=>:ge,:expr1=>val[0],:expr2=>val[2]}} + equalityexp: relationalexp + | equalityexp NE relationalexp {result={:type=>:ne,:expr1=>val[0],:expr2=>val[2]}} + | equalityexp EQ relationalexp {result={:type=>:eq,:expr1=>val[0],:expr2=>val[2]}} + andexp: equalityexp + | andexp AND equalityexp {result={:type=>:and,:expr1=>val[0],:expr2=>val[2]}} + xorexp: andexp + | xorexp XOR andexp {result={:type=>:xor,:expr1=>val[0],:expr2=>val[2]}} + orexp: xorexp + | orexp OR xorexp {result={:type=>:or,:expr1=>val[0],:expr2=>val[2]}} + landexp: orexp + | landexp LAND orexp {result={:type=>:land,:expr1=>val[0],:expr2=>val[2]}} + lorexp: landexp + | exp LOR landexp {result={:type=>:lor,:expr1=>val[0],:expr2=>val[2]}} + assignexp: lorexp + | IDENT EQUALS expression {result={:type=>:assign,:name=>val[0],:expr=>val[2]}} + | IDENT SETEQ expression {result={:type=>:assign,:name=>val[0],:expr=>{:type=>val[1],:expr1=>{:type=>:var,:name=>val[0]},:expr2=>val[2]}}} + expression: assignexp + | expression COMMA expression {result={:type=>:comma,:expr1=>val[0],:expr2=>val[2]}} + +end + +---- header + require "./lexer.rb" + +---- inner + def initialize() + @yydebug=true + end + def parse(input) + scan_str(input) + end