<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Compiler on liubang's blog</title><link>https://blog.liubang.cc/tags/compiler/</link><description>Recent content in Compiler on liubang's blog</description><generator>Hugo</generator><language>en</language><copyright>Copyright © 2019-2026 LiuBang. All Rights Reserved.</copyright><lastBuildDate>Wed, 29 Nov 2017 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.liubang.cc/tags/compiler/index.xml" rel="self" type="application/rss+xml"/><item><title>PHP7虚拟机</title><link>https://blog.liubang.cc/posts/php/2017-11-29-php7%E8%99%9A%E6%8B%9F%E6%9C%BA/</link><pubDate>Wed, 29 Nov 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/php/2017-11-29-php7%E8%99%9A%E6%8B%9F%E6%9C%BA/</guid><description><![CDATA[<p>原文地址<a href="http://nikic.github.io/2017/04/14/PHP-7-Virtual-machine.html" target="_blank" rel="noopener noreferrer">http://nikic.github.io/2017/04/14/PHP-7-Virtual-machine.html<i class="fas fa-external-link-square-alt ms-1"></i></a></p>
<p>写这篇文章的目的是基于 php7，阐述 Zend Virtual Machine 的内部实现。这不是一篇综合描述，我将尽可能地覆盖到所有重要的部分和细节。</p>
<p>本文的描述对象是 php7.2 版本，但是几乎所有的特性都已经应用在了 php7.0/7.1 中了。然而，它们同 php5.x 系列 VM 的不同之处同样也很重要，我会很有耐心的同步描述。</p>
<p>这篇文章主要是从指令的角度来阐述，只有在末尾花了少量篇幅描述了 C 语言实现 VM 的细节。但是在文章开始之前，我想先提供一些实现 VM 的主要代码文件：</p>
<ul>
<li><a href="https://github.com/php/php-src/blob/master/Zend/zend_vm_def.h" target="_blank" rel="noopener noreferrer">zend_vm_def.h<i class="fas fa-external-link-square-alt ms-1"></i></a>: VM 定义文件</li>
<li><a href="https://github.com/php/php-src/blob/master/Zend/zend_vm_execute.h" target="_blank" rel="noopener noreferrer">zend_vm_execute.h<i class="fas fa-external-link-square-alt ms-1"></i></a>: 生成的 VM</li>
<li><a href="https://github.com/php/php-src/blob/master/Zend/zend_vm_gen.php" target="_blank" rel="noopener noreferrer">zend_vm_gen.php<i class="fas fa-external-link-square-alt ms-1"></i></a>: VM 生成脚本</li>
<li><a href="https://github.com/php/php-src/blob/master/Zend/zend_execute.c" target="_blank" rel="noopener noreferrer">zend_execute.c<i class="fas fa-external-link-square-alt ms-1"></i></a>: 大多数直接支持的代码</li>
</ul>

<h2 id="opcodes" data-numberify>Opcodes<a class="anchor ms-1" href="#opcodes"></a></h2>
<p>首先我们来聊聊 opcode。&ldquo;Opcode&quot;是用来表示整个 VM 指令集（包括操作数）的，但是也可能仅仅就是指“真实的”操作码，这些操作码是一个很小的整数用来区分不同的指令类型。其具体的含义需要结合代码的上下文才能清楚。在程式码中，指令通常被称作&quot;oplines&rdquo;。</p>
<p>下面是<code>zend_op</code>的结构</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-1"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-1"> 1</a></span><span><span style="color:#c678dd">struct</span> <span style="color:#e06c75">_zend_op</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-2"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-2"> 2</a></span><span>    <span style="color:#c678dd">const</span> <span style="color:#e5c07b">void</span> <span style="color:#56b6c2">*</span><span style="color:#e06c75">handler</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-3"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-3"> 3</a></span><span>    <span style="color:#e06c75">znode_op</span> <span style="color:#e06c75">op1</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-4"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-4"> 4</a></span><span>    <span style="color:#e06c75">znode_op</span> <span style="color:#e06c75">op2</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-5"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-5"> 5</a></span><span>    <span style="color:#e06c75">znode_op</span> <span style="color:#e06c75">result</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-6"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-6"> 6</a></span><span>    <span style="color:#e5c07b">uint32_t</span> <span style="color:#e06c75">extended_value</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-7"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-7"> 7</a></span><span>    <span style="color:#e5c07b">uint32_t</span> <span style="color:#e06c75">lineno</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-8"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-8"> 8</a></span><span>    <span style="color:#e06c75">zend_uchar</span> <span style="color:#e06c75">opcode</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-9"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-9"> 9</a></span><span>    <span style="color:#e06c75">zend_uchar</span> <span style="color:#e06c75">op1_type</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-10"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-10">10</a></span><span>    <span style="color:#e06c75">zend_uchar</span> <span style="color:#e06c75">op2_type</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-11"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-11">11</a></span><span>    <span style="color:#e06c75">zend_uchar</span> <span style="color:#e06c75">result_type</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-12"><a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-12">12</a></span><span>};
</span></span></code></pre></div><p>由此看来，opcodes 本质上就是一个“三地址码”格式的指令。有一个<code>opcode</code>代表指令的类型，有两个输入操作数<code>op1</code>和<code>op2</code>和一个输出操作数<code>result</code>。</p>]]></description></item><item><title>基于c语言的编程语言开发</title><link>https://blog.liubang.cc/posts/compiler/2017-03-15-%E5%9F%BA%E4%BA%8Ec%E8%AF%AD%E8%A8%80%E7%9A%84%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91/</link><pubDate>Wed, 15 Mar 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/compiler/2017-03-15-%E5%9F%BA%E4%BA%8Ec%E8%AF%AD%E8%A8%80%E7%9A%84%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91/</guid><description><![CDATA[<h2 id="preface" data-numberify>Preface<a class="anchor ms-1" href="#preface"></a></h2>
<p>当今世道，各种高级语言百花齐放。然而会有人发出这样的疑问&ndash;计算机真的能够识别这么多语言吗？稍微有点常识的人都知道，这显然是不可能滴！在计算机的世界里，他们能够直接识别的只有机器语言。然而，由于机器语言对人类不够友好，所以人们才发明了汇编，c，Java&hellip;许许多多的人类易读的编程语言，所以我个人对编程语言的理解一直是其实他们就是机器语言的语法糖，而编程语言的创造过程，就是定义一种合理的，没有二义性的语法规则，然后就是通过直接或间接的方式实现该语法到机器语言的转换过程。既然是这样的话，那么我们就很容易想到，计算机语言是一个自我完善的过程：首先我们定了一种非常简单的 x1(这里只是用来举例说明，有没有 x 语言有待考证)语言，然后用机器语言实现了这个非常简单的 x1 语言的编译器，创造了 x1 语言，实现了非常简单的新特性，然后我们再用 x1 语言(相对于机器语言较高级)实现了另一些新的特性的 x2 语言的编译器，创造了 x2 语言，&hellip;，如此下去，人们创造了汇编语言，从而创造了 c 语言，接着创造了世界上最好的语言 PHP(不知道是不是真的，反正大家都习惯这么说)。
在各种高级语言越来越强大的今天，我们可能很难再会去接触最原始的东西，高度封装确实提高了生产力，降低了学习成本，但是也使得现代程序员将太多精力花在了各种说明书上，而不清楚其本质。
毕业一年多，工作了一年多，对于计算机编程有了自己的看法，不再像在大学的时候认识的那样肤浅，反而觉得大学中学习的知识才是真正的干货，不禁感叹曾经浪费掉了大好光阴。好在陶渊明有词云：“悟已往之不谏，知来者之可追”。
闲暇之余，扒开 PHP(这里之所以是 PHP 并不因为他是世界上最好的语言，只是因为我目前从事的是 PHP 开发的工作而已)源码，了解了其内部构造和实现原理，百看不一练。今天就初步学习 yacc/lex 了，记录在我的博客中，以便以后翻阅巩固。</p>

<h2 id="过程简述" data-numberify>过程简述<a class="anchor ms-1" href="#过程简述"></a></h2>
<p>一般来说编程语言的解释执行过程如下：</p>
<p><strong>ONE</strong>. 词法分析
将源代码拆分成若干 Token 的过程</p>
<p><strong>TWO</strong>.语法分析
将 Token 构建成 Syntax Tree 的过程</p>
<p><strong>THREE</strong>.生成执行码
生成可执行文件</p>

<h2 id="yaccyet-another-compiler-compiler" data-numberify>yacc（Yet Another Compiler Compiler）<a class="anchor ms-1" href="#yaccyet-another-compiler-compiler"></a></h2>
<p>下面是 wikipedia 中对 yacc 的描述</p>
<blockquote>
<p>Yacc is a computer program for the Unix operating system. It is a Look Ahead Left-to-Right (LALR) parser generator, generating a parser, the part of a compiler that tries to make syntactic sense of the source code, specifically a LALR parser, based on an analytic grammar written in a notation similar to Backus–Naur Form (BNF). Yacc itself used to be available as the default parser generator on most Unix systems, though it has since been supplanted as the default by more recent, largely compatible, programs.</p>]]></description></item></channel></rss>