我最近开始研究解析器和解析器生成器以及它们在 DSL 设计中的用途。为了让事情开始,并用一块石头杀死两只鸟,我通过从 peg.js 中窃取一些想法编写了一个纯 Ruby PEG 解析器 DSL。不同之处在于 peg.js 会将语法编译为 JavaScript,而我的库使用解释器模式与 Ruby 提供的一些语法糖相结合,以在纯 Ruby 中执行所有操作。这增加了一些我想避免的重要开销。
为了减少一些开销,我开始考虑将生成的一些解析表达式编译为较低级别的表示。我的一个想法是用来eval
评估某个对象的单例类中代码的字符串表示。这里有一些伪代码来演示这个过程:
# will be used to pass CompiledExpression instance to `eval`
def get_binding(instance)
instance.instance_eval { binding }
end
# an instance of this class will be used with `eval`
# to define an `execute` method
class CompiledExpression
attr_reader :code_repr
# need to instantiate with a string representation of
# the code we are going to use to define the `execute` method
def initialize(code)
@code_repr = code
end
end
# create the instance and define `execute` for that instance
# by evaluating the code representation
compiled_expr = CompiledExpression.new
# first way
eval "class << self; def execute; " +
"#{compiled_expr.code_repr}; end; end", get_binding(compiled_expr)
# second way
compiled_expr.instance_eval "class << self; " +
"def execute; #{compiled_expr.code_repr}: end; end"
# third way
compiled_expr.singleton_class.class_eval "def execute; " +
"#{compiled_expr.code_repr}; end"
# fourth way
compiled_expr.instance_eval "def execute; " +
"#{compiled_expr.code_repr}; end"
我想知道是否有其他/更好的方法来完成这样的代码生成?我对这些东西很陌生,所以我可能遗漏了一些明显的东西。