【原创】论另一种把Ruby翻译成其他语言的思路(不需要AST相关)
转载本文在您同意接受CC协议(NC-ND)情况下进行,可以参考:
http://creativecommons.org/licenses/by-nc-nd/3.0/
1. 目的。
给一个Ruby程序,把他翻译成语义上等价的其他程序。下面全部以C++为例,且不需要处理AST。
比如:
Ruby
1 | self.printf("%d\n", 3) |
翻译为C++
1 | printf("%d\n", 3) |
2. 类型系统:
指的是翻译时的变为目标源码字符串片段的固定方法(见7中的typed_output):
Numeric, Symbol翻译成对应的to_s。
String翻译成加双引号并且合适转义了的字符串。
有一个class Null, 实例对象为null,翻译成NULL或者0或者nullptr,表示空指针,
同时nil保留不能用于转换,如果出现,表示某一步类型推断失败了。
3.普通函数调用的翻译:
Ruby
1 | self.printf("%d\n", 3) |
通过method_missing或者printf定义的导入,处理成:
1 | self.fcall :printf, "%d\n", 3 |
fcall的实现是很容易的。
4.分支结构的翻译。
if是一个方法def ifelse(str,&block)
抽离了作用域的处理,相当于这样的工作:
1 2 3 4 5 6 7 | def ifelse(str) `if(#{expr(str)}){` yield true `}else{` yield false `}` end |
其中定义self.`为直接输出目标代码
使用时举例:
1 2 3 4 5 6 7 | self.ifelse some_expr do |result| if result self.printf("Hello\n") else self.printf("world\n") end end |
unless, case…when也是类似的方法
5.迭代结构的翻译。
while(until)是很简单的处理,不再赘述。
这里主要是说Ruby最常见的一种结构each(for)。
举例说明,(这里和Enumerable需要的each并不兼容,可以修改使之兼容)
1 2 3 4 5 6 7 8 9 10 11 | class ERange def initialize(x, y) #x...y @x, @y = x, y end def each name = auto_variable_name #分配变量名 `for(auto #{name} = #{@x}; #{name} != #{@y}; ++#{name}){` yield name `}` end end |
6.表达式的翻译。
在2的类型系统加上如下约定:
1 2 3 4 5 6 7 8 9 10 11 | def expr(obj) case obj when Array then obj.map{|x| expr(x)}.join else 按照2中的方法翻译 end end |
7. 常数组合的处理。
C++和很多语言有类似的机制如:
1 | int fd = open("test", O_CREAT|O_EXECL); |
其中open的第二个参数就是一个常数组合,
这里修改expr的定义为
1 2 3 4 5 6 7 8 9 10 11 | def expr(obj) case obj when Array then obj.map{|x| expr(x)}.join else typed_output(obj) end end |
其中typed_output的定义是:
1 2 3 4 5 6 7 8 9 10 11 12 | def typed_output(var) case typeof1(var) when :int, :float then var when :symbol then var.to_s when [:symbol] then var.map{|x| x.to_s}.join("|") when [:char] then @_.string(var) when ->a{Array === a && a[0]==:ref} then var.parent.to_s + var.name.to_s when :bool then var.to_s else raise "Does not know how to output #{var.to_s[0..10]} #{var.to_s.length > 10 ? '...' : ''} - #{typeof1(var).inspect} " end end |
请注意when [:symbol]的处理
至于typeof1的实现,是一种模式匹配的类型推断机制,不再详细说明。
这样就可以写为
1 | self[:fd] = self.open("test", [:O_CREAT, :O_EXECL]) |
至于self.[]=(:fd, …)这个[]=方法,涉及到作用域的设计,(也可以不用作用域的约束,直接把fd当做一个符号而不进行是否定义的检查)。
8. 表达式树的处理。
可能更加希望写成i>4而不是[i, :>, 4],可以用下面的方法代入7中的系统处理
1 2 3 | def >(obj); [self.content, :>, obj]; end |
9. 函数与匿名函数的处理。
Todo.
10. 协程式的风格的处理。
1 2 3 4 5 6 7 | do_something{ xxx }.andThen{ xxx }.andThen{ yyy } |
Todo.