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