Created
July 21, 2014 20:47
-
-
Save hxy9243/d172eb92c11618a47964 to your computer and use it in GitHub Desktop.
LLVM parser grammar specification
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class ModuleParser | |
| def initialize | |
| @ast_prog = nil | |
| @ast_queue = Array.new | |
| @any_text = SeqRule.new(:line, [Any]) | |
| @ignore_rest = RepRule.new(:line, @any_text) | |
| pri_type = AltRule.new(:line, [Literal["i64"], Literal["i32"], Literal["i8"], Literal["i1"], Literal["void"], Literal["double"], Literal["float"]]) | |
| pointers = RepRule.new(:line, SeqRule.new(:line, [Literal['*']]), [], lambda {|w| return w[0]!='*'}) | |
| @type = SeqRule.new(:line, [pri_type, pointers]) { |*r| | |
| t = GetASTType(r[0].tname, r[1].size) | |
| @ast_queue << t | |
| } | |
| @basic_array_rule = SeqRule.new(:line, [Number, Literal['x'], @type]) | |
| @array_type = SeqRule.new(:line, [Literal["["], RepRule.new(:line, @any_text, ']'), Literal["]"]]) { |*r| | |
| a = [] | |
| r[1].each {|e| a << e[0]} | |
| t = GenArrayType(a) | |
| @ast_queue << t | |
| } | |
| @operant = SeqRule.new(:line, [AltRule.new(:line, [Number, Text])]) { | |
| |*r| @ast_queue << ToCVarName(r[0]) | |
| } | |
| getelementptr_index = SeqRule.new(:line, [ Literal[','], @type, @operant]) { |*r| | |
| op = @ast_queue.pop | |
| @ast_queue.pop | |
| op | |
| } | |
| getelementptr_body = SeqRule.new(:line, [@array_type, Literal['*'], @operant, RepRule.new(:line, getelementptr_index, ')')]) { |*r| | |
| name = @ast_queue.pop # pop var | |
| @ast_queue.pop # pop array type | |
| idx = r[3] | |
| raise "unsupported getelementptr index" if idx[0] != 0 | |
| idx.shift | |
| var = Ast::VarAcc.new(GetVarDecl(name)) | |
| idx.each {|i| | |
| if i.is_a? Fixnum | |
| e = Ast::NumConst.new(i) | |
| else | |
| e = Ast::VarAcc.new(GetVarDecl(i)) | |
| end | |
| var.add_dim(e) | |
| } | |
| @ast_queue << Ast::OpExpr.new('&', var) | |
| } | |
| @expr_getelementptr_call = SeqRule.new(:line, [Literal["getelementptr"], RepRule.new(:line, @any_text, '('), Literal["("], | |
| getelementptr_body , Literal[")"]]) | |
| operator_cmp1 = AltRule.new(:line, [Literal["icmp"]]) | |
| operator_cmp2 = AltRule.new(:line, [Literal["eq"], Literal["ne"], Literal["slt"], Literal["sle"], Literal["sge"], Literal["sgt"]]) | |
| @operator_cmp = SeqRule.new(:line, [operator_cmp1, operator_cmp2]) { |*r| | |
| case r[1].tname | |
| when "eq" | |
| @ast_queue << "==" | |
| when "ne" | |
| @ast_queue << "!=" | |
| when "slt" | |
| @ast_queue << "<" | |
| when "sle" | |
| @ast_queue << "<=" | |
| when "sgt" | |
| @ast_queue << ">=" | |
| when "sge" | |
| @ast_queue << ">=" | |
| else | |
| raise "unknown compare symbol '#{r[1].tname}'" | |
| end | |
| } | |
| @operator_add = SeqRule.new(:line, [Literal["add"], @any_text]) { | |
| @ast_queue << "+" | |
| } | |
| @operator_mul = SeqRule.new(:line, [Literal["mul"], AltRule.new(:line, [Literal["nsw"]])]) { | |
| @ast_queue << "*" | |
| } | |
| @operator_sub = SeqRule.new(:line, [Literal["sub"], AltRule.new(:line, [Literal["nsw"]])]) { | |
| @ast_queue << "-" | |
| } | |
| @operator_div = SeqRule.new(:line, [Literal["sdiv"] ]) { | |
| @ast_queue << "/" | |
| } | |
| @operator_rem = SeqRule.new(:line, [Literal["srem"]]) { | |
| @ast_queue << "%" | |
| } | |
| @operator_fadd = SeqRule.new(:line, [Literal["fadd"]]) { | |
| @ast_queue << "+" | |
| } | |
| @operator_fmul = SeqRule.new(:line, [Literal["fmul"]]) { | |
| @ast_queue << "*" | |
| } | |
| @operator_rule = AltRule.new(:line, [ | |
| @operator_cmp, | |
| @operator_div, | |
| @operator_mul, | |
| @operator_sub, | |
| @operator_add, | |
| @operator_rem, | |
| @operator_fadd, | |
| @operator_fmul, | |
| ]) | |
| #@align = SeqRule.new(:line, [Literal["align"], Number]) | |
| @expr_getelementptr = SeqRule.new(:line, [Literal["getelementptr"], RepRule.new(:line, @any_text, '['), getelementptr_body]) { | |
| @ast_queue << "getelementptr" | |
| } | |
| @expr_load = SeqRule.new(:line, [Literal["load"], @type, AltRule.new(:line, [@operant, @expr_getelementptr_call]), @ignore_rest]) { | |
| @ast_queue << "load" | |
| } | |
| @expr_alloca = SeqRule.new(:line, [Literal["alloca"], AltRule.new(:line, [@type, @array_type]), @ignore_rest]) { | |
| @ast_queue << "alloca" | |
| } | |
| convert_op = AltRule.new(:line, [Literal["bitcast"], Literal["sext"], Literal["sitofp"], Literal["fptosi"]]) | |
| @expr_convert = SeqRule.new(:line, [convert_op, @type, @operant, Literal["To"], @type]) { | |
| @ast_queue << "convert" | |
| } | |
| @expr_op2 = SeqRule.new(:line, [@operator_rule, @type, @operant, Literal[","], @operant]) { | |
| @ast_queue << "op2" | |
| } | |
| call_func_par_rule = SeqRule.new(:line, [@type, AltRule.new(:line, [@operant, @expr_getelementptr_call])]) { | |
| t, v = @ast_queue.pop(2) | |
| if v.is_a? Ast::OpExpr # getelementptr | |
| @ast_queue << v | |
| else | |
| acc = GetVarAcc(v) | |
| if acc.is_a? Ast::VarAcc and t != acc.var.var_type | |
| raise "mismatched type" if GetPointToType(t) != acc.var.var_type | |
| @ast_queue << Ast::OpExpr.new("&", acc) | |
| else | |
| @ast_queue << acc | |
| end | |
| end | |
| } | |
| call_func_pars_rule = AltRule.new(:line, [ | |
| SeqRule.new(:line, [Literal[")"], @ignore_rest]), | |
| SeqRule.new(:line, [call_func_par_rule, RepRule.new(:line, SeqRule.new(:line, [Literal[","], call_func_par_rule]), ")"), Literal[")"], @ignore_rest]) | |
| ]) | |
| @call_func_rule = SeqRule.new(:line, [ Text, Literal["("], call_func_pars_rule]) {|*r| @call_func_name = r[0][1..-1]} | |
| @expr_call = SeqRule.new(:line, [Literal["call"], @type, RepRule.new(:line, @any_text, "@"), @call_func_rule]) { | |
| @ast_queue << "call" | |
| } | |
| @expr_rule = AltRule.new(:line, [ | |
| @expr_load, | |
| @expr_alloca, | |
| @expr_convert, | |
| @expr_call, | |
| @expr_op2, | |
| @expr_getelementptr, | |
| ]) | |
| @stmt_assign = SeqRule.new(:line, [Text, Literal["="], @expr_rule]) { |*r| | |
| name = ToCVarName(r[0]) | |
| op_type = @ast_queue.pop | |
| case op_type | |
| when "convert" | |
| type = @ast_queue.pop | |
| val = @ast_queue.pop | |
| rhs = GetVarAcc(val) | |
| when "alloca" | |
| type = @ast_queue.shift | |
| rhs = nil | |
| when "load" | |
| s_type = @ast_queue.shift | |
| s_var = @ast_queue.shift | |
| s_decl = GetVarDecl(s_var) | |
| type = GetPointToType(s_type) | |
| if s_var.is_a? Ast::OpExpr # getelementptr | |
| rhs = s_var.rand1 | |
| rhs.detach_me | |
| elsif s_decl.is_a? Decl::Var and s_decl.var_type.is_a? Decl::PrimType | |
| if s_type != s_decl.var_type | |
| raise "mismatched type" if type != s_decl.var_type | |
| rhs = Ast::VarAcc.new(s_decl) | |
| else | |
| rhs = Ast::DerefAcc.new(s_decl, 1) | |
| end | |
| else | |
| raise "unhandled load" | |
| end | |
| when "call" | |
| type = @ast_queue.shift | |
| rhs = Ast::Call.new(@call_func_name) | |
| @ast_queue.each {|p| | |
| raise "wrong paramter" if not p.is_a? Ast::Expr | |
| rhs.add_param(p) | |
| } | |
| when "op2" | |
| op = @ast_queue.shift | |
| type = @ast_queue.shift | |
| o1, o2 = @ast_queue.shift(2) | |
| rhs = Ast::OpExpr.new(op, GetVarAcc(o1), GetVarAcc(o2)) | |
| when "getelementptr" | |
| rhs = @ast_queue.shift | |
| acc = rhs.rand1 | |
| if acc.var.var_type.is_a?Decl::ArrayType | |
| if acc.dim == acc.var.var_type.num_dim | |
| type = Decl::PrimType.get_prim_type(acc.var.var_type.elem_type.type_name, 1) | |
| else | |
| raise "unhandled getelementptr" | |
| end | |
| else | |
| raise "unhandled getelementptr" | |
| end | |
| else | |
| raise "unknown assign stmt" | |
| end | |
| decl = Decl::Var.new(name, type) | |
| @ast_func.add_sym(decl) | |
| lhs = Ast::VarAcc.new(decl) | |
| @ast_func.add_child(Ast::AssignStat.new(rhs, lhs)) if rhs | |
| @ast_queue.clear | |
| } | |
| #store | |
| store_src_target = SeqRule.new(:line, [@type, AltRule.new(:line, [@operant, @expr_getelementptr_call])]) | |
| @stmt_store = SeqRule.new(:line, [Literal["store"], store_src_target, Literal[","], store_src_target, @ignore_rest]) { | |
| s_type = @ast_queue.shift | |
| s_var = @ast_queue.shift | |
| t_type = @ast_queue.shift | |
| t_var = @ast_queue.shift | |
| if s_var.is_a? Ast::OpExpr | |
| raise "incorrect store source" if not s_var.rand1.is_a? Ast::VarAcc | |
| src = s_var | |
| #src.detach_me | |
| else | |
| src = GetVarAcc(s_var) | |
| end | |
| t_decl = GetVarDecl(t_var) | |
| if t_decl.is_a? Decl::Var and t_decl.var_type.is_a? Decl::PrimType | |
| if GetPointToType(t_type) == t_decl.var_type | |
| raise "mismatched type" if s_type != t_decl.var_type | |
| tgt = Ast::VarAcc.new(t_decl) | |
| elsif t_type == t_decl.var_type | |
| tgt = Ast::DerefAcc.new(t_decl, 1) | |
| else | |
| raise "mismatched type" | |
| end | |
| elsif t_var.is_a? Ast::OpExpr # getelementptr | |
| raise "incorrect store target" if not t_var.rand1.is_a? Ast::VarAcc | |
| tgt = t_var.rand1 | |
| tgt.detach_me | |
| else | |
| raise "unhandled store" | |
| end | |
| #print src.c_dump, tgt.c_dump | |
| @ast_func.add_child(Ast::AssignStat.new(src, tgt)) | |
| @ast_queue.clear | |
| } | |
| #label | |
| @stmt_label = SeqRule.new(:line, [Label] ) { |r| | |
| @ast_func.add_child( Ast::LabelStat.new(ToCLabelName(r))) | |
| } | |
| #branch | |
| br_target = SeqRule.new(:line, [ Literal["label"], Text ]) {|*r| @ast_queue << ToCLabelName(r[1])} | |
| br_cond = SeqRule.new(:line, [ Literal["i1"], @operant, Literal[","], br_target, Literal[","], br_target]) | |
| @stmt_br = SeqRule.new(:line, [ Literal["br"], AltRule.new(:line, [ br_target, br_cond ]) ]) { | |
| if @ast_queue.size == 3 | |
| cond = GetVarAcc(@ast_queue.shift) | |
| @ast_func.add_child(Ast::GotoStat.new(@ast_queue.shift, cond, @ast_queue.shift)) | |
| else | |
| raise "wrong br instr" if @ast_queue.size != 1 | |
| @ast_func.add_child(Ast::GotoStat.new(@ast_queue[0])) | |
| end | |
| @ast_queue.clear | |
| } | |
| #retrun | |
| @stmt_ret = SeqRule.new(:line, [ Literal["ret"], AltRule.new(:line, [ Literal["void"], SeqRule.new(:line, [@type, @operant]) ])]) { || | |
| expr = nil | |
| expr = GetVarAcc(@ast_queue.pop()) if not @ast_queue.empty? | |
| @ast_func.add_child(Ast::ReturnStat.new(expr)) | |
| @ast_queue.clear | |
| } | |
| #call | |
| @stmt_call = SeqRule.new(:line, [@expr_call]) { |*r| | |
| type = @ast_queue.shift | |
| @ast_queue.pop # | |
| rhs = Ast::Call.new(@call_func_name) | |
| @ast_queue.each {|p| | |
| raise "wrong paramter #{p}" if not p.is_a? Ast::Expr | |
| rhs.add_param(p) | |
| } | |
| @ast_func.add_child(Ast::AssignStat.new(rhs)) | |
| @ast_queue.clear | |
| } | |
| @stmt_rule = AltRule.new(:line, [ | |
| @stmt_label, | |
| @stmt_store, | |
| @stmt_br, | |
| @stmt_ret, | |
| @stmt_assign, | |
| @stmt_call, | |
| ] ) | |
| func_par_rule = SeqRule.new(:line, [@type, @operant]) { | |
| t, o = @ast_queue.pop(2) | |
| @ast_queue << Decl::Var.new(o, t) | |
| } | |
| func_par_ignore = SeqRule.new(:line, [Literal["..."]]) | |
| func_pars_rule = AltRule.new(:line, [ SeqRule.new(:line, [Literal[")"]]), | |
| SeqRule.new(:line, [func_par_rule, RepRule.new(:line, SeqRule.new(:line, [Literal[","], AltRule.new(:line, [func_par_rule, func_par_ignore])]), ")"), Literal[")"]]) | |
| ] | |
| ) | |
| @func_name_rule = SeqRule.new(:line, [ Text, Literal["("], func_pars_rule]) { | |
| |*r| @curr_func_name = r[0][1..-1] | |
| } | |
| #@func_attr = AltRule.new(:line, [Literal["noreturn"], Literal["nounwind"], Literal["readonly"], Literal["readnone"]]) | |
| @func_head_rule = SeqRule.new(:line, [ Literal["define"], @type, @func_name_rule, @any_text, Literal["{"] ]) { | |
| #NewFuncHeadAction() | |
| func_ret_type = @ast_queue.shift | |
| @ast_func = Ast::Func.new(@curr_func_name) | |
| #func_par_list = | |
| func_type = Decl::FuncType.new(func_ret_type) | |
| @ast_queue.each { |v| | |
| func_type.add_param(v) | |
| } | |
| @ast_func.add_func_type(func_type) | |
| @ast_prog.add_child(@ast_func) | |
| @ast_queue.clear | |
| } | |
| @func_body_rule = RepRule.new(:file, @stmt_rule, "}" ) | |
| @func_def_rule = SeqRule.new(:file, [ @func_head_rule, @func_body_rule, Literal["}"] ] ) { | |
| @ast_queue.clear | |
| } | |
| func_decl_pars_rule = AltRule.new(:line, [ SeqRule.new(:line, [Literal[")"]]), | |
| SeqRule.new(:line, [@type, RepRule.new(:line, SeqRule.new(:line, [Literal[","], AltRule.new(:line, [@type, func_par_ignore])]), ")"), Literal[")"]]) | |
| ] | |
| ) | |
| func_decl_name_rule = SeqRule.new(:line, [ Text, Literal["("], func_decl_pars_rule]) | |
| @func_decl_rule = SeqRule.new(:line, [Literal["declare"], @type, func_decl_name_rule, @ignore_rest]) { | |
| @ast_queue.clear | |
| } | |
| @func_rule = AltRule.new(:file, [@func_def_rule, @func_decl_rule]) | |
| funcs_rule = RepRule.new(:file, @func_rule, "attributes") | |
| @target_rule = SeqRule.new(:line, [ Literal['target'], RepRule.new(:line, @any_text) ] ) | |
| targets_rule = RepRule.new(:file, @target_rule, ['@', 'define']) | |
| value_initer = AltRule.new(:line, [ Str, Number, Literal["zeroinitializer"] ]) | |
| @globalvar_rule = SeqRule.new(:line, [ Text, Literal['='], RepRule.new(:line, @any_text, ['constant', 'global']), | |
| AltRule.new(:line, [Literal['global'], Literal['constant']]), | |
| AltRule.new(:line, [@type, @array_type]), value_initer, @ignore_rest]) { |*r| | |
| name = ToCVarName(r[0]) | |
| type = @ast_queue.pop | |
| if type.is_a? Decl::ArrayType | |
| var = Decl::Var.new(name, type) | |
| @ast_prog.add_sym(var) | |
| elsif type.is_a? Decl::PrimType | |
| var = Decl::Var.new(name, type) | |
| @ast_prog.add_sym(var) | |
| else | |
| raise "unhandled glaoble varibale type" | |
| end | |
| v = r[-2] | |
| if v == Literal["zeroinitializer"] | |
| elsif v.is_a? Fixnum | |
| rhs = Ast::NumConst.new(v) | |
| else | |
| rhs = Ast::StrConst.new(v) | |
| end | |
| @ast_prog.set_initializer(name, rhs) | |
| @ast_queue.clear | |
| } | |
| globalvars_rule = RepRule.new(:file, @globalvar_rule, ['define']) | |
| attr_rule = SeqRule.new(:line, [ Literal['attributes'], @ignore_rest] ) | |
| attrs_rule = RepRule.new(:file, attr_rule) | |
| @module_rule = SeqRule.new(:file, [ targets_rule, globalvars_rule, funcs_rule, attrs_rule] ) | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment