我在哪里可以找到有关高级语言编译器的信息? [英] where can I find information about high level language compilers?

查看:122
本文介绍了我在哪里可以找到有关高级语言编译器的信息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道编译器如何将C或Pascal转换为机器代码,但不知道OOP编译器如何转换新概念,例如

1-Generic(Method,Types,Classes)

2-Delegate

3-Dynamic Binding

4 - 继承(可能很容易)

5用儿童作为父母,父母为子女(多态性)

我问的是母语这样的C ++而不是C#或JAVA

------

提前谢谢

I know how compiler translate C or Pascal to machine code, but not how OOP compiler translate new concepts such as
1-Generic (Method,Types,Classes)
2-Delegate
3-Dynamic Binding
4-Inheritance (may be easy)
5-use child as parent and parent as child (Polymorphism)
I ask about native language such C++ not C# or JAVA
------
Thanks in advance

推荐答案

非常简短:



Very briefly:

  1. 泛型:它取决于平台和技术。在所有情况下,泛型都不在机器代码中表示。在像Ada或C ++(不适用于.NET)的技术中,它就像预处理一样。由于通用类型和方法的所有实例都是通过整个程序静态知道的,因此只有实际的完整类型生成到机器代码中,并且它们完全等同于非泛型方法和函数。 />


    在基于CIL(Java,.NET)字节代码的平台中,泛型实际上是以字节代码或CIL语言保存的,并且是在编译时生成的。机器代码的生成发生在运行时。请参阅:

    http://en.wikipedia.org/wiki/Just-in -time_compilation [ ^ ]。



    通常,JIT编译基于每个方法进行。只要首先需要一些调用,就会在代码执行时实例化泛型类型,并在机器代码中实例化和生成泛型函数。不仅不完整的类型实际上不存在,但即使该方法也可能永远不会在机器代码中生成,如果它们存在于字节码/ CIL上但在给定的运行时期间实际上没有被调用。非常有趣的机制。



    课程是一个非常不同的问题。没有虚方法的类就像常规结构一样,它们的静态方法就像常规的非OOP方法;它们与机器代码的角度没有任何区别。也不是静态方法,只有一个简单的转折:它们完全等同于静态方法,但有一点不同:它们有一个隐式参数,它是一个引用或指向表示该类实例的某个对象的指针。我在过去的答案中进一步详细解释了这一点:

    什么使静态方法可以访问? [ ^ ],

    Catch 22 - 当使用它们的功能变为静态时,指向接口对象的指针会死亡。 [ ^ ],

    C#windows基于此关键字及其在应用程序中的用途 [ ^ ]。



    但虚拟功能完全不同。最好在动态绑定(dispatch)中提及它们。
  2. 现在,代表。



    委托类型不存在在机器代码中。它们只是必需方法签名的符号,仅供编译器用于验证。并且委托实例具有非常不同的运行时类型,甚至与委托类型无关。



    委托实例类型的解剖(I不得不诉诸这个丑陋的术语,以避免与代表类型的混淆)在不同的系统中是非常不同的。下面是一个最简单的委托的表示方式:这是1)带有this参数的方法的结构,在调用期间可以为null(参见上面的链接),2)某个类型实例的引用/指针(这个类型与委托类型和委托实例的类型无关,实现委托方法,这个实例可以为null,它在委托实例的调用期间作为this参数传递,3)当然,实例类型本身,因为第2项中提到的引用应该引用一些对象。当然,如果引用为null,则实例不存在。
  3. 当委托方法是静态时,会创建带有this的委托实例。



    也许,最复杂的委托实例变体是由.NET实现的。它不是上面描述的一种方法,而是携带其他(单方法,也称为 sinlge-cast )委托实例的整个集合。此集合称为调用列表。另外,委托instanced是 immutable :当某些代码将新项添加到调用列表时,一个全新的实例将创建所有旧项和一个新项。旧实例稍后在无法访问时被丢弃(垃圾收集)。它同时可以访问,因为不同线程中的某些代码可能正在调用它。



    这样的调用(一般情况下, multi-委托实例化会导致调用整个列表的单播委托实例。



    请参阅我的委托实例的性质部分CodeProject文章:动态方法调度程序 [ ^ ]。



  4. 您可能意味着动态调度 http:// en .wikipedia.org / wiki / Dynamic_binding_%28computer_science%29 [ ^ ]。



    参见:<啊ref =http://en.wikipedia.org/wiki/Late_binding> http://en.wikipedia.org/wiki/Late_binding [ ^ ]。



    在经典的OOP中,它通过虚方法表
    。这些表也是不同的(多重继承,如果它被支持,使它们更加复杂)。这只是方法地址和其他一些数据的结构(例如RTTI: http://en.wikipedia.org/wiki/ RTTI [ ^ ])。



    机制非常简单,但用文字甚至代码来解释都很难。这个主要OOP机制的最佳解释很简单:如果你有一个后期绑定代码并且在调试器下逐步运行它,你可以理解它。那些最终第一次得到它的人通常会经历一些智力冲击。所有程序员都应该理解它。 (太多了,甚至可能不是多数,但他们只是在程序员的位置上工作,但实际上并不是真正的开发人员。)



    虚拟方法表实际上是一个对象,每种类型一个(类/结构)。



    请参阅: http://en.wikipedia.org/wiki/Virtual_method_table [ ^ ],

    http://en.wikipedia.org/wiki/Virtual_function [ ^ ]。
  5. 遗产。实际上,并不那么容易。这是OOP的听说。如果涉及虚拟方法,则继承会创建新的虚方法表。如果覆盖某些方法,则替换表的各个成员。理解这一点很重要:调用分派的机制是动态的,但是所有表在编译结束时都是静态知道的,因此在运行时它们永远不会被更改。所以,在机器代码中,它们只是静态结构。



    记住我上面提到的关于实例方法的内容:传递隐式this参数。这指向类型实例,并且实例具有指向其虚方法表的指针/引用。因此,如果方法是虚拟的,则会间接调用它。变量的编译类型是1,但其运行时类型不同,因此从祖先类型调用某些方法,有些方法从层次结构中稍后的类型调用。它是否为您提供了OOP实际工作方式的基本提示?



    如果没有一些示例说明如何应用此技术,这实际上很难理解。我不认为我应该立刻解释它。
  6. 多态性是上面解释的后期绑定的结果。它本身不是一个单独的机制。当你有一组具有相同编译时类型的对象时它会发生(它可以是一个根祖先类型,但不仅仅是这个,因为还有接口,你没有提到),但不同的运行时类型。此时,机器代码表示的讨论已经结束,因为上面已经描述了所有内容。



    剩下的考虑因素仅与使用此机器代码有关:



    想象一下你在某个循环中遍历整个集合。您调用了一些方法,但只调用了根父类中可用的方法(其他方法不适用,因为某些对象不具备它们)。当您调用这些方法时,它们会调用其他方法,这些方法是后期绑定的,并且特定于不同的运行时类型。这样,您可以使用一些通用界面处理整个设置,但不同的对象会以不同的特定方式响应您的呼叫。



    它使界面无法通过图片。接口产生一些不同类型的多态性。我认为足够了,但你可以看到我过去的答案:

    [ ^ ]时,

    抽象类和接口之间的区别,如果它们具有相同的no方法和var [ ^ ],

    如何决定选择抽象类或接口 [ ^ ],

    和这个是关于基于接口的多态性:接口和多态性 [ ^ ]。
  1. Generics: it depends on platform and technology. In all cases, generics are not represented in machine code. In technologies like Ada or C++ (not for .NET), it is like preprocessing. As all the instantiations of generic types and methods are statically known through the whole program, only the actual complete types are generated into machine code, and they are fully equivalent to non-generic methods and functions.

    In platforms based on byte code of CIL (Java, .NET), generics are actually preserved in byte code or CIL language and are generated as a result of compilation. The generation of machine code happens during run-time. Please see:
    http://en.wikipedia.org/wiki/Just-in-time_compilation[^].

    Typically, JIT-compilations happens on per-method basis. As soon as some call is first needed, the generic type is instantiated as the code goes and the generic function is instantiated and generated in machine code. Not only incomplete type do not physically exist, but even the method may never be generated in machine code, if they exist on bytecode/CIL but not actually called during given runtime. Pretty interesting mechanism.

    Classes is a very different issue. Classes with no virtual method are like regular structures, and their static methods are like regular non-OOP methods; their is no any difference from the machine code perspective. Not static methods, too, with one simple twist: they are fully equivalent to static methods, with one difference: they have one implicit parameter which is a reference or a pointer to some object representing the instance of the class. I explained it in further detail in my past answers:
    What makes static methods accessible?[^],
    Catch 22 - Pointers to interface objects die when function using them is made static.[^],
    C# windows base this key word related and its uses in the application[^].

    But virtual function are completely different. It''s better to mention them in connection to dynamic binding (dispatch).
  2. Now, delegates.

    The delegate types do not exist in machine code. They are just notations of required method signatures, used only by compilers for validation. And the delegate instances have very different runtime types, not even related to delegate types.

    The anatomy of the types of delegate instances (I have to resort to this ugly term to avoid confusion with delegate types) is very different in different systems. Here is how a simplest delegate is represented: this is a structure of 1) some method with "this" parameter which can be null during the call (see my links above), 2) a reference/pointer to the instance of some type (this type is unrelated to delegate type and to the type of the delegate instance) implementing the delegate method, this instance can be null, it is passed as "this" parameter during the invocation of delegate instance, 3) and, naturally, the instance of the type itself, as the reference mentioned in item #2 should reference some object. Naturally, the instance does not exist if the reference is null.
  3. The delegate instance with null "this" is created when the delegate method is static.

    Probably, the most complex variant of delegate instances is implemented by .NET. Instead of one method described above, it carries the whole collection of other (single-method, also called sinlge-cast) delegate instances. This collection is called "invocation list". Also, delegate instanced are immutable: when some code adds a new item to the invocation list, a brand-new instance will all old items and one new item is created. The old instance is later discarded (garbage-collected) when it becomes unreachable. It can be reachable in the meanwhile, because some code in a different thread might be invoking it.

    The invocation of such (in general case, multi-cast) delegate instanced causes calls of the single-cast delegate instances of the whole list.

    Please see the section on the nature of delegate instances in my CodeProject article: Dynamic Method Dispatcher[^].

  4. You probably mean dynamic dispatch: http://en.wikipedia.org/wiki/Dynamic_binding_%28computer_science%29[^].

    See also: http://en.wikipedia.org/wiki/Late_binding[^].

    In classical OOP, it is done via virtual method table. Those tables are also different (multiple inheritance, if it is supported, makes them much more complex). This is nothing but a structure of method addresses and some other data (such as RTTI: http://en.wikipedia.org/wiki/RTTI[^]).

    The mechanism is pretty simple, but it''s pretty hard to explain in words or even code. The best explanation of this main OOP mechanism is simple: you can understand it all if you have a late binding code and run it under the debugger step by step. Those who finally first get it usually experience some intellectual shock. All programmers should understand it well. (Too many, may be even majority don''t, but they only work on programmer''s positions but actually are not real developers.)

    Virtual method table is actually an object, one per type (class/structure).

    Please see: http://en.wikipedia.org/wiki/Virtual_method_table[^],
    http://en.wikipedia.org/wiki/Virtual_function[^].
  5. Inheritance. Actually, not so easy. This is the heard of OOP. If virtual methods are involved, inheritance creates a new virtual method table. If some methods are overridden, respective members of the table are replaced. It''s important to understand: the mechanism of the call dispatch is dynamic, but all tables are statically known by the end of compilation, so they are never changed during runtime. So, in machine code, they are just static structures.

    Remember what I mentioned about instance methods above: the pass implicit "this" parameter. This points to the type instance, and the instance has a pointer/reference to its virtual method table. So, if a method is virtual, it is called indirectly. Compile-type of the variable is one, but its run-time type is different, so some methods are called from the ancestor type(s), some from a type later in the hierarchy. Does it gives you a basic hint on how OOP actually works?

    This is actually hard to appreciate without some example showing how this technique is applied. I don''t think I should try to explain it all at once.
  6. Polymorphism is a consequence of late binding explained above. It is itself is not a separate mechanism. It takes place when you have some set of objects of the same compile-time type (it can be a root ancestor type, but not just this, because there are also interfaces which you did not mention), but different runtime types. At this point, the talking of machine-code representation is over, because everything is already described above.

    The remaining considerations are only about the use of this machine code:

    Imagine you traverse the whole set in some loop. You call some methods, but only those available in the root parent class (others are not applicable, as some object won''t have them). When you call those methods, they call other methods, which are late bound and are specific for different runtime types. This way, you handle the whole set with some common interface, but the different object respond to your calls in their different specific ways.

    It leaves the interfaces out of picture. Interfaces generate somewhat different kind of polymorphism. I think think enough is enough, but you can see my past answers:
    When we use abstract and when we use interface...?[^],
    Difference between abstract class and interface if they have same no of methods and var[^],
    How to decide to choose Abstract class or an Interface[^],
    and this one is about interface-based polymorphism: Interfaces and Polymorphism[^].





这就是现在的全部。我非常努力地写了一遍,几乎没有计划。所以,你有些事情不清楚(甚至不太准确),对不起。欢迎您提出后续问题。



-SA


这篇关于我在哪里可以找到有关高级语言编译器的信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆