我不是函数程序员。因此,我对模式匹配,模式或任何其他东西不是很熟悉。对我而言,我只理解好的旧switch声明的概念。
编译器将如何实现match语句?match和switch到底有什么区别?有一个GNU C99扩展,允许您在切换的情况下具有范围,两者之间是否有区别:
match x {
0 ... 9 => ...,
_ => ...,
}
Run Code Online (Sandbox Code Playgroud)
和
switch (x) {
case 0 ... 9: ...; break;
default: ...; break;
}
Run Code Online (Sandbox Code Playgroud)
请注意,第二个片段是带有此GNU扩展名的简单C开关。
我正在尝试解析程序的 AST 以获得一种虚构的语言,具体来说,我正在尝试模拟作用域,因此您输入一个函数,然后推送一个新的作用域,当该函数完成时当访问者访问时,它会弹出范围。一个重要的方面是,当我们推送一个新的作用域时,会currentScope设置一个指针,它指向我们当前正在查看的作用域。当我们弹出作用域时,当前作用域被设置为“外部”:
class Scope:
outer : Scope
inner : Scope
Run Code Online (Sandbox Code Playgroud)
这将在多次传递中发生,但第一次传递重要的是它构建通用范围树。我要问的问题是如何按照创建树的顺序遍历这棵树?例如:
{ // global scope
{ // a
{ // aa
}
{ // ab
}
}
{ // b
}
}
Run Code Online (Sandbox Code Playgroud)
当我再次传递完全相同的节点集时,理论上它们会给我相同的范围树,但我想保留我们在每次传递中收集和存储每个范围的所有数据。换句话说,当第二次或第三遍发生在 AST 上时,当我们访问 a 时,currentScope = a,当我们访问 aa 时,currentScope = aa。这可能吗?我真的对这个想法感到困惑,整个递归方面真的让我很困惑,我似乎不知道如何做到这一点。
这是我尝试过的:
class Scope
outer : Scope
inner : Scope
siblings : []Scope
Scope(outer):
this.outer = outer
push_idx = 0
push_scope()
// set global scope
if current is null
global = new Scope(null)
current = …Run Code Online (Sandbox Code Playgroud) 我看到ARC是不时使用的首字母缩写,但是例如在Rust中,它是“原子引用计数”,而在Swift或ObjC中,它们称为“自动引用计数”。到底有什么区别?据我所知,它们的行为方式似乎相同。
我可以将抽象语法树直接翻译成SSA格式,还是需要创建控制流图,然后从所述CFG创建静态单一分配表?
在控制流图的上下文中:我如何为类似c的程序表示这一点?我想我可以存储每个函数中所有基本块的CFG图,但是当我调用一个函数时,这可能会使事情复杂化.我能想到的另一种方法是整个程序的CFG,即所有源文件,但是我如何存储有关函数的信息?我可以在基本块(即父节点)中存储指向该函数的指针吗?
如果我从CFG生成SSA,我是否需要担心代表语句控制流的CFG?我想我只需要代表基本的块控制流程.
我在这里看到了这个问题,但它没有特别详细地回答我的想法。如果像 Go 或 C++11 这样的语言不使用像 Damas-Milner 这样的推理算法,它们究竟做了什么?我认为这不像在右手边输入类型那么简单,因为如果你有这样的东西怎么办:
5 + 3.4
Run Code Online (Sandbox Code Playgroud)
编译器如何破译那是什么类型?有没有什么算法不那么简单
if left is integer and right is float:
return float;
if left is float and right is integer:
return float;
etc... for every possible pattern
Run Code Online (Sandbox Code Playgroud)
如果你能用简单的术语解释事情,那就太好了。我没有详细研究编译器构造或任何理论主题,我也不会真正讲函数式语言或复杂的数学符号。
在Rust中,您只能使用特征来指定类型限制,例如:<T: A + B>,A和B必须是traits,它们不能是i32或者是原始类型f64.
trait Foo {}
impl Foo for i32 {}
fn blah<T: i32>(val: T) {
// ^^^ works if this is Foo
println!("hello\n");
}
fn main() {
let toast: i32 = 33;
blah(toast);
}
Run Code Online (Sandbox Code Playgroud)
你可以通过实现原语的特征来解决这个问题,但为什么语言的设计者不会让你使用原语作为限制呢?
说我有一个指针地图,我new怎么能遍历这个地图并干净地删除它们?这是我尝试过的:
std::map<std::string, Foo*> foos;
foos.insert(std::make_pair("blah", new Foo()));
for (auto& f : foos) {
delete f;
}
Run Code Online (Sandbox Code Playgroud)
虽然它似乎不起作用,但我收到以下错误.
$ g++ test.c -std=c++14
test.c: In function 'int main()':
test.c:12:12: error: type 'struct std::pair<const std::basic_string<char>, Foo*>' argument given to 'delete', expected pointer
delete f;
Run Code Online (Sandbox Code Playgroud)