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 0000000..6721483 Binary files /dev/null and b/out differ diff --git a/out.asm b/out.asm new file mode 100644 index 0000000..5073014 --- /dev/null +++ b/out.asm @@ -0,0 +1,20 @@ +.globl _main +_main: +push rbp +mov rbp,rsp +mov rax,2 +push rax +mov rax,[rbp-8] +push rax +mov rax,2 +pop rcx +add rax,rcx +mov [rbp-8],rax +mov rax,[rbp-8] +mov rsp,rbp +pop rbp +ret +mov rax,0 +mov rsp,rbp +pop rbp +ret diff --git a/parser.rb b/parser.rb new file mode 100644 index 0000000..1969d02 --- /dev/null +++ b/parser.rb @@ -0,0 +1,593 @@ +# +# DO NOT MODIFY!!!! +# This file is automatically generated by Racc 1.4.14 +# from Racc grammer file "". +# + +require 'racc/parser.rb' + + require "./lexer.rb" + +class CX86 < Racc::Parser + +module_eval(<<'...end parser.y/module_eval...', 'parser.y', 59) + def initialize() + @yydebug=true + end + def parse(input) + scan_str(input) + end +...end parser.y/module_eval... +##### State transition tables begin ### + +racc_action_table = [ + 15, 22, 21, 71, 63, 47, 14, 39, 67, 17, + 18, 19, 20, 15, 22, 21, 54, 55, 40, 14, + 93, 36, 17, 18, 19, 20, 22, 21, 48, 33, + 22, 21, 41, 41, 17, 18, 19, 20, 17, 18, + 19, 20, 33, 41, 53, 41, 41, 53, 54, 55, + 52, 22, 21, 52, 33, 22, 21, 41, 33, 17, + 18, 19, 20, 17, 18, 19, 20, 22, 21, 56, + 57, 58, 59, 60, 61, 17, 18, 19, 20, 33, + 22, 21, 41, 33, 56, 57, 58, 59, 17, 18, + 19, 20, 43, 21, 11, 33, 43, 21, 68, 69, + 17, 18, 19, 20, 17, 18, 19, 20, 33, 43, + 21, 54, 55, 43, 21, 54, 55, 17, 18, 19, + 20, 17, 18, 19, 20, 43, 21, 54, 55, 43, + 21, 60, 61, 17, 18, 19, 20, 17, 18, 19, + 20, 43, 21, 9, 8, 43, 21, 7, 63, 17, + 18, 19, 20, 17, 18, 19, 20, 43, 21, 64, + 3, 43, 21, 65, 6, 17, 18, 19, 20, 17, + 18, 19, 20, 43, 21, 3, 4, 43, 21, 62, + 66, 17, 18, 19, 20, 17, 18, 19, 20, 43, + 21, 65, 64, 43, 21, 62, nil, 17, 18, 19, + 20, 17, 18, 19, 20, 43, 21, nil, nil, 43, + 21, nil, nil, 17, 18, 19, 20, 17, 18, 19, + 20, 43, 21, nil, nil, 43, 21, nil, nil, 17, + 18, 19, 20, 17, 18, 19, 20, 43, 21, nil, + nil, 43, 21, nil, nil, 17, 18, 19, 20, 17, + 18, 19, 20, 43, 21, 56, 57, 58, 59, 53, + nil, 17, 18, 19, 20, 52, 49, 50, 51, 49, + 50, 51, 49, 50, 51 ] + +racc_action_check = [ + 13, 13, 13, 46, 30, 22, 13, 15, 38, 13, + 13, 13, 13, 11, 11, 11, 83, 83, 16, 11, + 92, 12, 11, 11, 11, 11, 69, 69, 22, 13, + 48, 48, 46, 38, 69, 69, 69, 69, 48, 48, + 48, 48, 11, 16, 79, 92, 70, 80, 26, 26, + 79, 47, 47, 80, 69, 21, 21, 72, 48, 47, + 47, 47, 47, 21, 21, 21, 21, 14, 14, 85, + 85, 85, 85, 28, 28, 14, 14, 14, 14, 47, + 41, 41, 73, 21, 27, 27, 27, 27, 41, 41, + 41, 41, 56, 56, 9, 14, 58, 58, 39, 39, + 56, 56, 56, 56, 58, 58, 58, 58, 41, 59, + 59, 81, 81, 60, 60, 82, 82, 59, 59, 59, + 59, 60, 60, 60, 60, 66, 66, 84, 84, 18, + 18, 87, 87, 66, 66, 66, 66, 18, 18, 18, + 18, 19, 19, 8, 6, 20, 20, 4, 89, 19, + 19, 19, 19, 20, 20, 20, 20, 61, 61, 90, + 0, 49, 49, 91, 3, 61, 61, 61, 61, 49, + 49, 49, 49, 50, 50, 2, 1, 51, 51, 88, + 33, 50, 50, 50, 50, 51, 51, 51, 51, 52, + 52, 32, 31, 53, 53, 29, nil, 52, 52, 52, + 52, 53, 53, 53, 53, 54, 54, nil, nil, 55, + 55, nil, nil, 54, 54, 54, 54, 55, 55, 55, + 55, 57, 57, nil, nil, 65, 65, nil, nil, 57, + 57, 57, 57, 65, 65, 65, 65, 64, 64, nil, + nil, 63, 63, nil, nil, 64, 64, 64, 64, 63, + 63, 63, 63, 62, 62, 86, 86, 86, 86, 25, + nil, 62, 62, 62, 62, 25, 24, 24, 24, 77, + 77, 77, 78, 78, 78 ] + +racc_action_pointer = [ + 158, 176, 173, 161, 147, nil, 140, nil, 138, 88, + nil, 11, 14, -2, 64, 4, 9, nil, 126, 138, + 142, 52, -5, nil, 251, 247, 29, 63, 48, 168, + -24, 163, 161, 148, nil, nil, nil, nil, -1, 89, + nil, 77, nil, nil, nil, nil, -2, 48, 27, 158, + 170, 174, 186, 190, 202, 206, 89, 218, 93, 106, + 110, 154, 250, 238, 234, 222, 122, nil, nil, 23, + 12, nil, 23, 48, nil, nil, nil, 254, 257, 32, + 35, 92, 96, -3, 108, 48, 234, 106, 152, 120, + 130, 133, 11, nil ] + +racc_action_default = [ + -50, -50, -1, -50, -50, -2, -50, 94, -50, -50, + -3, -50, -50, -5, -50, -50, -50, -11, -50, -50, + -50, -50, -16, -17, -21, -24, -27, -32, -35, -37, + -39, -41, -43, -50, -45, -48, -4, -6, -50, -50, + -10, -50, -12, -16, -13, -14, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -7, -8, -50, + -49, -15, -46, -47, -18, -19, -20, -22, -23, -25, + -26, -28, -29, -30, -31, -33, -34, -36, -38, -40, + -42, -44, -50, -9 ] + +racc_goto_table = [ + 38, 1, 88, 5, 42, 44, 45, 46, 81, 82, + 83, 84, 12, 89, 37, 79, 80, 85, 86, 77, + 78, 90, 91, 10, 87, nil, nil, 70, nil, nil, + nil, nil, nil, 72, 73, 74, 75, 76, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 92 ] + +racc_goto_check = [ + 6, 1, 13, 1, 7, 7, 7, 6, 10, 10, + 10, 10, 4, 14, 4, 9, 9, 11, 11, 8, + 8, 15, 16, 3, 12, nil, nil, 6, nil, nil, + nil, nil, nil, 6, 6, 7, 7, 7, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 6 ] + +racc_goto_pointer = [ + nil, 1, nil, 14, 1, nil, -14, -14, -33, -39, + -48, -43, -38, -61, -51, -44, -44, nil, nil ] + +racc_goto_default = [ + nil, nil, 2, nil, nil, 13, 16, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 34, 35 ] + +racc_reduce_table = [ + 0, 0, :racc_error, + 1, 36, :_reduce_1, + 2, 36, :_reduce_2, + 5, 37, :_reduce_3, + 3, 38, :_reduce_4, + 1, 39, :_reduce_5, + 2, 39, :_reduce_6, + 3, 40, :_reduce_7, + 3, 40, :_reduce_8, + 5, 40, :_reduce_9, + 2, 40, :_reduce_10, + 1, 42, :_reduce_11, + 2, 42, :_reduce_12, + 2, 42, :_reduce_13, + 2, 42, :_reduce_14, + 3, 42, :_reduce_15, + 1, 42, :_reduce_16, + 1, 43, :_reduce_none, + 3, 43, :_reduce_18, + 3, 43, :_reduce_19, + 3, 43, :_reduce_20, + 1, 44, :_reduce_none, + 3, 44, :_reduce_22, + 3, 44, :_reduce_23, + 1, 45, :_reduce_none, + 3, 45, :_reduce_25, + 3, 45, :_reduce_26, + 1, 46, :_reduce_none, + 3, 46, :_reduce_28, + 3, 46, :_reduce_29, + 3, 46, :_reduce_30, + 3, 46, :_reduce_31, + 1, 47, :_reduce_none, + 3, 47, :_reduce_33, + 3, 47, :_reduce_34, + 1, 48, :_reduce_none, + 3, 48, :_reduce_36, + 1, 49, :_reduce_none, + 3, 49, :_reduce_38, + 1, 50, :_reduce_none, + 3, 50, :_reduce_40, + 1, 51, :_reduce_none, + 3, 51, :_reduce_42, + 1, 52, :_reduce_none, + 3, 52, :_reduce_44, + 1, 53, :_reduce_none, + 3, 53, :_reduce_46, + 3, 53, :_reduce_47, + 1, 41, :_reduce_none, + 3, 41, :_reduce_49 ] + +racc_reduce_n = 50 + +racc_shift_n = 94 + +racc_token_table = { + false => 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