<?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>PKU 编译原理实践 on farmer3-c Blog</title><link>https://farmer3-c.github.io/tags/pku-%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86%E5%AE%9E%E8%B7%B5/</link><description>Recent content in PKU 编译原理实践 on farmer3-c Blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Wed, 10 Jun 2026 21:55:22 +0000</lastBuildDate><atom:link href="https://farmer3-c.github.io/tags/pku-%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86%E5%AE%9E%E8%B7%B5/index.xml" rel="self" type="application/rss+xml"/><item><title>编译实践Lv1.main函数</title><link>https://farmer3-c.github.io/posts/%E7%BC%96%E8%AF%91%E5%AE%9E%E8%B7%B5lv1main%E5%87%BD%E6%95%B0/</link><pubDate>Wed, 10 Jun 2026 21:55:22 +0000</pubDate><guid>https://farmer3-c.github.io/posts/%E7%BC%96%E8%AF%91%E5%AE%9E%E8%B7%B5lv1main%E5%87%BD%E6%95%B0/</guid><description>&lt;h1 id="目的"&gt;目的&lt;/h1&gt;
&lt;p&gt;实现一个能处理 main 函数和 return 语句的编译器.编译器可以将如下的 SysY 程序:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;int main() {
// 注释也应该被删掉哦
return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;编译为对应的 Koopa IR:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;fun @main(): i32 {
%entry:
ret 0
}
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id="实现"&gt;实现&lt;/h1&gt;
&lt;h2 id="lv12-词法语法分析初见"&gt;Lv1.2. 词法/语法分析初见&lt;/h2&gt;
&lt;p&gt;我使用项目提供的c++模板，直接执行：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;make
build/compiler -koopa hello.c -o hello.koopa
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;int main() { return 0; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是因为默认的模板使用string存放ast，所以输出的ast也是string形式：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;CompUnit
: FuncDef {
ast = unique_ptr&amp;lt;string&amp;gt;($1);
}
;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="lv13-解析-main-函数"&gt;Lv1.3. 解析 main 函数&lt;/h2&gt;
&lt;p&gt;这里设计一个ast用于输出程序的语法结构，教程写的已经很详细了：写一个头文件来定义AST,对于头文件重复声明的问题，加上&lt;code&gt;#pragma once&lt;/code&gt;就可以解决。&lt;/p&gt;
&lt;p&gt;我是这样定义基类和子类进行构造的：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;// 所有 AST 的基类
class BaseAST {
public:
virtual ~BaseAST() = default;
virtual void Dump() const = 0;
};
// CompUnit 是 BaseAST
class CompUnitAST : public BaseAST {
public:
// 用智能指针管理对象
std::unique_ptr&amp;lt;BaseAST&amp;gt; func_def;
void Dump() const override {
std::cout &amp;lt;&amp;lt; &amp;#34;CompUnitAST { &amp;#34;;
func_def-&amp;gt;Dump();
std::cout &amp;lt;&amp;lt; &amp;#34; }&amp;#34;;
}
};
……
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;同时，修改参数类型的相关声明：比如&lt;code&gt;%parse-param { std::unique_ptr&amp;lt;string&amp;gt; &amp;amp;ast } &lt;/code&gt;改为&lt;code&gt;%parse-param { std::unique_ptr&amp;lt;BaseAST&amp;gt; &amp;amp;ast } &lt;/code&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="目的">目的</h1>
<p>实现一个能处理 main 函数和 return 语句的编译器.编译器可以将如下的 SysY 程序:</p>
<pre tabindex="0"><code>int main() {
  // 注释也应该被删掉哦
  return 0;
}
</code></pre><p>编译为对应的 Koopa IR:</p>
<pre tabindex="0"><code>fun @main(): i32 {
%entry:
  ret 0
}
</code></pre><h1 id="实现">实现</h1>
<h2 id="lv12-词法语法分析初见">Lv1.2. 词法/语法分析初见</h2>
<p>我使用项目提供的c++模板，直接执行：</p>
<pre tabindex="0"><code>make
build/compiler -koopa hello.c -o hello.koopa
</code></pre><p>输出：</p>
<pre tabindex="0"><code>int main() { return 0; }
</code></pre><p>这是因为默认的模板使用string存放ast，所以输出的ast也是string形式：</p>
<pre tabindex="0"><code>CompUnit
  : FuncDef {
    ast = unique_ptr&lt;string&gt;($1);
  }
  ;
</code></pre><h2 id="lv13-解析-main-函数">Lv1.3. 解析 main 函数</h2>
<p>这里设计一个ast用于输出程序的语法结构，教程写的已经很详细了：写一个头文件来定义AST,对于头文件重复声明的问题，加上<code>#pragma once</code>就可以解决。</p>
<p>我是这样定义基类和子类进行构造的：</p>
<pre tabindex="0"><code>// 所有 AST 的基类
class BaseAST {
 public:
  virtual ~BaseAST() = default;
  virtual void Dump() const = 0;
};

// CompUnit 是 BaseAST
class CompUnitAST : public BaseAST {
 public:
  // 用智能指针管理对象
  std::unique_ptr&lt;BaseAST&gt; func_def;

    void Dump() const override {
    std::cout &lt;&lt; &#34;CompUnitAST { &#34;;
    func_def-&gt;Dump();
    std::cout &lt;&lt; &#34; }&#34;;
  }
};
……
</code></pre><p>同时，修改参数类型的相关声明：比如<code>%parse-param { std::unique_ptr&lt;string&gt; &amp;ast } </code>改为<code>%parse-param { std::unique_ptr&lt;BaseAST&gt; &amp;ast } </code></p>
<p>make之后就会输出<code>CompUnitAST { FuncDefAST { FuncTypeAST { int }, main, BlockAST { StmtAST { 0 } } } } </code>。</p>
<h2 id="lv14-ir-生成">Lv1.4. IR 生成</h2>
<p>我采用定义 AST 一样定义表示 Koopa IR 的数据结构, 然后遍历 AST 输出这种结构, 再遍历这种结构输出字符串。</p>
<p>类似的，写一个KoopaIR头文件，定义它的结构：</p>
<pre tabindex="0"><code>// Value 是所有指令和常量的基类
class Value {
 public:
  virtual ~Value() = default;
  virtual void Dump() const = 0;
};

// 整数常量
class Integer : public Value {
 public:
  int value;
  
  Integer(int v) : value(v) {}
  
  void Dump() const override {
    std::cout &lt;&lt; value;
  }
};
</code></pre><p>接着完成<code>GenerateIR</code>的工作，完成遍历 AST 生成 IR，由于只需要识别main函数就可以了，复杂一些的递归之类的暂时不需要写。</p>
<pre tabindex="0"><code>main.cpp
  │
  ├─ yyparse(ast)          // 调用 Bison/Flex 解析源码 → 得到 AST
  │
  ├─ GenerateIR(*ast)      // ← 遍历 AST，生成 Koopa IR (Program)
  │     └─ IRGenerator.cpp
  │          ├─ dynamic_cast&lt;CompUnitAST*&gt; 取出 func_def
  │          ├─ dynamic_cast&lt;FuncDefAST*&gt;  取出 ident + block
  │          ├─ dynamic_cast&lt;BlockAST*&gt;    取出 stmt
  │          ├─ dynamic_cast&lt;StmtAST*&gt;     取出 num
  │          └─ 构建 Return(Integer(num)) → BasicBlock → Function → Program
  │
  └─ program-&gt;Dump()       // 以文本格式输出 Koopa IR
</code></pre><h2 id="lv15-测试">Lv1.5. 测试</h2>
<p>有一个小问题，模板给出的sysy.l没有给出注释块的定义，需要我们自己加上<code>BlockComment  &quot;/*&quot;(.|\n)*?&quot;*/&quot;</code>,否则测试的时候会有一个测试点不过。</p>
<p>测试结果：
<img alt="1" loading="lazy" src="/img/pku-compiler/image.png"></p>
]]></content:encoded></item><item><title>编译实践Lv0. 环境配置</title><link>https://farmer3-c.github.io/posts/lv0-/</link><pubDate>Sat, 14 Feb 2026 00:08:02 +0800</pubDate><guid>https://farmer3-c.github.io/posts/lv0-/</guid><description>&lt;h1 id="目的"&gt;目的&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;配置实验环境的 Docker 容器, 并学习 Docker 的基本使用方法.&lt;/li&gt;
&lt;li&gt;认识编译实践中用到的编译器中间表示: Koopa IR.&lt;/li&gt;
&lt;li&gt;认识编译实践中开发的编译器的目标架构: RISC-V.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="配置实验环境的-docker-容器-并学习-docker-的基本使用方法"&gt;配置实验环境的 Docker 容器, 并学习 Docker 的基本使用方法.&lt;/h2&gt;
&lt;h3 id="安装docker-desktop"&gt;安装Docker Desktop&lt;/h3&gt;
&lt;h3 id="使用docker"&gt;使用docker&lt;/h3&gt;
&lt;h4 id="一镜像相关常用命令"&gt;一、镜像相关常用命令&lt;/h4&gt;
&lt;p&gt;镜像是容器的 “模板”，所有容器都基于镜像创建，这部分是基础操作。&lt;/p&gt;
&lt;h5 id="1-拉取镜像下载到本地"&gt;1. 拉取镜像（下载到本地）&lt;/h5&gt;
&lt;p&gt;如果本地没有该镜像，先从 Docker 仓库拉取（如果是私有仓库，需先&lt;code&gt;docker login&lt;/code&gt;）：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;powershell&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 拉取指定镜像（格式：docker pull 镜像名:标签，latest是默认标签可省略）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;pull&lt;/span&gt; &lt;span class="n"&gt;maxxing&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;compiler-dev&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 简写（省略latest，效果同上）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;pull&lt;/span&gt; &lt;span class="n"&gt;maxxing&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;compiler-dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;作用：把远程仓库的&lt;code&gt;maxxing/compiler-dev&lt;/code&gt;镜像下载到本地，后续创建容器无需重复下载；&lt;/li&gt;
&lt;li&gt;场景：首次使用该镜像、需要更新镜像版本时。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="2-查看本地镜像"&gt;2. 查看本地镜像&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;powershell&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 查看所有本地镜像（重点看REPOSITORY、TAG、IMAGE ID）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 过滤查看指定镜像（只显示maxxing/compiler-dev）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt; &lt;span class="n"&gt;maxxing&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;compiler-dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;输出示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;REPOSITORY TAG IMAGE ID CREATED SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;maxxing/compiler-dev latest 5bcecbbe34b6 3 months ago 4.14GB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;场景：确认镜像是否已下载、查看镜像 ID / 大小等信息。&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="目的">目的</h1>
<ul>
<li>配置实验环境的 Docker 容器, 并学习 Docker 的基本使用方法.</li>
<li>认识编译实践中用到的编译器中间表示: Koopa IR.</li>
<li>认识编译实践中开发的编译器的目标架构: RISC-V.</li>
</ul>
<h2 id="配置实验环境的-docker-容器-并学习-docker-的基本使用方法">配置实验环境的 Docker 容器, 并学习 Docker 的基本使用方法.</h2>
<h3 id="安装docker-desktop">安装Docker Desktop</h3>
<h3 id="使用docker">使用docker</h3>
<h4 id="一镜像相关常用命令">一、镜像相关常用命令</h4>
<p>镜像是容器的 “模板”，所有容器都基于镜像创建，这部分是基础操作。</p>
<h5 id="1-拉取镜像下载到本地">1. 拉取镜像（下载到本地）</h5>
<p>如果本地没有该镜像，先从 Docker 仓库拉取（如果是私有仓库，需先<code>docker login</code>）：</p>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 拉取指定镜像（格式：docker pull 镜像名:标签，latest是默认标签可省略）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">pull</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span><span class="err">:</span><span class="n">latest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 简写（省略latest，效果同上）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">pull</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>作用：把远程仓库的<code>maxxing/compiler-dev</code>镜像下载到本地，后续创建容器无需重复下载；</li>
<li>场景：首次使用该镜像、需要更新镜像版本时。</li>
</ul>
<h5 id="2-查看本地镜像">2. 查看本地镜像</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 查看所有本地镜像（重点看REPOSITORY、TAG、IMAGE ID）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">images</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 过滤查看指定镜像（只显示maxxing/compiler-dev）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">images</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>
<p>输出示例：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">REPOSITORY             TAG       IMAGE ID       CREATED        SIZE
</span></span><span class="line"><span class="cl">maxxing/compiler-dev   latest    5bcecbbe34b6   3 months ago   4.14GB
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>场景：确认镜像是否已下载、查看镜像 ID / 大小等信息。</p>
</li>
</ul>
<h5 id="3-查看镜像详情">3. 查看镜像详情</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 查看镜像的详细信息（创建时间、作者、启动命令等）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">inspect</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span><span class="err">:</span><span class="n">latest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 简化查看：只提取镜像的默认启动命令 </span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">inspect</span> <span class="p">-</span><span class="n">-format</span><span class="p">=</span><span class="s1">&#39;{{.Config.Cmd}}&#39;</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span><span class="err">:</span><span class="n">latest</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>场景：排查镜像默认启动命令、确认镜像配置是否符合预期。</li>
</ul>
<h5 id="4-删除镜像">4. 删除镜像</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 删除指定镜像（需确保无容器关联，否则加-f强制删除）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">rmi</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span><span class="err">:</span><span class="n">latest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 或用镜像ID删除（更精准）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">rmi</span> <span class="n">5bcecbbe34b6</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>注意：如果有容器使用该镜像，需先删除容器（参考下文 “删除容器” 命令）；</li>
<li>场景：清理无用镜像、释放磁盘空间。</li>
</ul>
<h4 id="二容器相关常用命令基于-maxxingcompiler-dev-创建容器">二、容器相关常用命令（基于 maxxing/compiler-dev 创建容器）</h4>
<p>容器是镜像的 “运行实例”，这部分是使用镜像的核心操作。</p>
<h5 id="1-创建并启动容器">1. 创建并启动容器</h5>
<p>这是最常用的命令，直接创建并进入容器，避免启动后退出：</p>
<p>powershell</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 方式1：临时交互（推荐测试用，退出容器即停止）</span>
</span></span><span class="line"><span class="cl"><span class="c"># -it：交互终端，/bin/sh：适配Alpine镜像（无bash），--name：自定义容器名（避免随机名称）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">run</span> <span class="n">-it</span> <span class="p">-</span><span class="n">-name</span> <span class="nb">compiler-dev</span><span class="n">-container</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span><span class="err">:</span><span class="n">latest</span> <span class="p">/</span><span class="n">bin</span><span class="p">/</span><span class="n">sh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 方式2：后台运行（长期使用，可随时进入）</span>
</span></span><span class="line"><span class="cl"><span class="c"># -d：后台运行，--restart=always：容器开机自启（可选）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">run</span> <span class="n">-d</span> <span class="n">-it</span> <span class="p">-</span><span class="n">-name</span> <span class="nb">compiler-dev</span><span class="n">-container</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span><span class="err">:</span><span class="n">latest</span> <span class="p">/</span><span class="n">bin</span><span class="p">/</span><span class="n">sh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 方式3：映射端口/目录（映射本地目录到容器）</span>
</span></span><span class="line"><span class="cl"><span class="c"># -v：本地目录:Docker容器目录（实现文件共享），-p：本地端口:容器端口（网络映射）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">run</span> <span class="n">-it</span> <span class="n">-v</span> <span class="n">D:</span><span class="p">\</span><span class="n">DockerData</span><span class="p">\</span><span class="n">code</span><span class="err">:</span><span class="p">/</span><span class="n">root</span><span class="p">/</span><span class="n">code</span> <span class="n">-p</span> <span class="mf">8080</span><span class="err">:</span><span class="mf">80</span> <span class="p">-</span><span class="n">-name</span> <span class="nb">compiler-dev</span><span class="n">-container</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span><span class="err">:</span><span class="n">latest</span> <span class="p">/</span><span class="n">bin</span><span class="p">/</span><span class="n">sh</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>
<p>参数说明：</p>
<ul>
<li><code>-i</code>：保持输入交互；<code>-t</code>：分配伪终端；<code>-d</code>：后台运行；</li>
<li><code>--name</code>：给容器起固定名称（方便后续操作，比如<code>compiler-dev-container</code>）；</li>
<li><code>-v</code>：目录挂载（本地<code>D:\DockerData\code</code>和容器<code>/root/code</code>双向同步）；</li>
<li><code>-p</code>：端口映射（访问本地 8080 端口等价于访问容器 80 端口）；</li>
</ul>
</li>
<li>
<p>场景：</p>
<ul>
<li>临时测试镜像：用方式 1；</li>
<li>长期运行服务：用方式 2；</li>
<li>需要读写本地文件 / 暴露端口：用方式 3。</li>
</ul>
</li>
</ul>
<h5 id="2-查看容器状态">2. 查看容器状态</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 查看运行中的容器</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="nb">ps
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 查看所有容器（包括已停止的）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="nb">ps </span><span class="n">-a</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 只查看指定容器的状态（用容器名/ID）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="nb">ps </span><span class="n">-a</span> <span class="p">-</span><span class="n">-filter</span> <span class="s2">&#34;name=compiler-dev-container&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>
<p>输出关键字段：</p>
<ul>
<li><code>STATUS</code>：<code>Up X minutes</code>（运行中）/<code>Exited (0) X minutes ago</code>（已退出）；</li>
<li><code>NAMES</code>：容器名（compiler-dev-container）；</li>
<li><code>CONTAINER ID</code>：容器 ID（比如 37dadd02cbf2）；</li>
</ul>
</li>
<li>
<p>场景：确认容器是否运行、查找容器 ID / 名称。</p>
</li>
</ul>
<h5 id="3-进入运行中的容器">3. 进入运行中的容器</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 进入后台运行的容器</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">exec</span> <span class="n">-it</span> <span class="nb">compiler-dev</span><span class="n">-container</span> <span class="p">/</span><span class="n">bin</span><span class="p">/</span><span class="n">sh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 或用容器ID进入（比如容器ID是37dadd02cbf2）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">exec</span> <span class="n">-it</span> <span class="n">37dadd02cbf2</span> <span class="p">/</span><span class="n">bin</span><span class="p">/</span><span class="n">sh</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>注意：必须确保容器处于 “Up” 状态（运行中），否则会提示 “container is not running”；</li>
<li>场景：在运行中的容器内执行命令、操作文件。</li>
</ul>
<h5 id="4-启动--停止--重启容器">4. 启动 / 停止 / 重启容器</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 启动已停止的容器（用容器名/ID）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="nb">start compiler-dev</span><span class="n">-container</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 停止运行中的容器</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">stop</span> <span class="nb">compiler-dev</span><span class="n">-container</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 重启容器（先停止再启动）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">restart</span> <span class="nb">compiler-dev</span><span class="n">-container</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>
<p>场景：</p>
<ul>
<li>容器意外停止：用<code>docker start</code>重启；</li>
<li>调整容器配置后：用<code>docker restart</code>生效；</li>
<li>不需要容器运行时：用<code>docker stop</code>停止（释放资源）。</li>
</ul>
</li>
</ul>
<h5 id="5-查看容器日志排查问题">5. 查看容器日志（排查问题）</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 查看容器的全部日志</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">logs</span> <span class="nb">compiler-dev</span><span class="n">-container</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 实时查看日志（类似Linux tail -f）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">logs</span> <span class="o">-f</span> <span class="nb">compiler-dev</span><span class="n">-container</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 查看最新100行日志</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">logs</span> <span class="p">-</span><span class="n">-tail</span><span class="p">=</span><span class="mf">100</span> <span class="nb">compiler-dev</span><span class="n">-container</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>场景：容器启动失败、运行异常时，通过日志排查原因（比如命令执行错误、文件缺失）。</li>
</ul>
<h5 id="6-删除容器">6. 删除容器</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 先停止容器，再删除（推荐）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">stop</span> <span class="nb">compiler-dev</span><span class="n">-container</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="nb">rm compiler-dev</span><span class="n">-container</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 强制删除运行中的容器（不推荐，可能丢失数据）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="nb">rm </span><span class="o">-f</span> <span class="nb">compiler-dev</span><span class="n">-container</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 批量删除所有已停止的容器（清理垃圾）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">container</span> <span class="n">prune</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>场景：容器不再使用、需要重新创建容器时。</li>
</ul>
<h5 id="7挂载目录">7.挂载目录</h5>
<ul>
<li>场景：需要在容器内读写本地文件时，通过目录挂载实现（比如<code>-v D:\DockerData\code:/root/code</code>）。</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 挂载本地目录到容器（读写模式）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">run</span> <span class="n">-it</span> <span class="n">-v</span> <span class="n">D:</span><span class="p">\</span><span class="n">DockerData</span><span class="p">\</span><span class="n">code</span><span class="err">:</span><span class="p">/</span><span class="n">root</span><span class="p">/</span><span class="n">code</span> <span class="p">-</span><span class="n">-name</span> <span class="nb">compiler-dev</span><span class="n">-container</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span><span class="err">:</span><span class="n">latest</span> <span class="p">/</span><span class="n">bin</span><span class="p">/</span><span class="n">sh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 挂载本地目录到容器（只读模式）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">run</span> <span class="n">-it</span> <span class="n">-v</span> <span class="n">D:</span><span class="p">\</span><span class="n">DockerData</span><span class="p">\</span><span class="n">code</span><span class="err">:</span><span class="p">/</span><span class="n">root</span><span class="p">/</span><span class="n">code</span><span class="err">:</span><span class="n">ro</span> <span class="p">-</span><span class="n">-name</span> <span class="nb">compiler-dev</span><span class="n">-container</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span><span class="err">:</span><span class="n">latest</span> <span class="p">/</span><span class="n">bin</span><span class="p">/</span><span class="n">sh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 基于maxxing/compiler-dev镜像创建名为mycp的交互式容器，挂载Windows D盘指定目录到容器/root/sysy-make-template，容器退出后自动删除并进入Shell交互界面</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">run</span> <span class="n">-it</span> <span class="p">-</span><span class="n">-rm</span> <span class="p">-</span><span class="n">-name</span> <span class="n">mycp</span> <span class="n">-v</span> <span class="p">/</span><span class="n">d</span><span class="p">/</span><span class="n">githubprojects</span><span class="p">/</span><span class="nb">sysy-make</span><span class="n">-template:</span><span class="p">/</span><span class="n">root</span><span class="p">/</span><span class="nb">sysy-make</span><span class="n">-template</span> <span class="n">maxxing</span><span class="p">/</span><span class="nb">compiler-dev</span> <span class="p">/</span><span class="n">bin</span><span class="p">/</span><span class="n">sh</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="三运维管理常用命令">三、运维管理常用命令</h4>
<h5 id="1-查看-docker-系统信息">1. 查看 Docker 系统信息</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 查看Docker整体信息（版本、镜像/容器数量、存储驱动等）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">info</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 查看Docker版本</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">version</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>场景：排查 Docker 环境问题、确认版本兼容性。</li>
</ul>
<h5 id="2-清理-docker-垃圾释放磁盘空间">2. 清理 Docker 垃圾（释放磁盘空间）</h5>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 清理所有无用的镜像、容器、网络、缓存（安全）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">system</span> <span class="n">prune</span> <span class="n">-a</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 只清理镜像缓存（保留镜像/容器）</span>
</span></span><span class="line"><span class="cl"><span class="n">docker</span> <span class="n">builder</span> <span class="n">prune</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>注意：<code>docker system prune -a</code>会删除未使用的镜像，执行前确认无需保留。</li>
</ul>
<h4 id="总结">总结</h4>
<p>以<code>maxxing/compiler-dev:latest</code>为例，核心常用命令可归纳为 3 类：</p>
<ol>
<li><strong>镜像操作</strong>：<code>docker pull</code>（拉取）→ <code>docker images</code>（查看）→ <code>docker inspect</code>（详情）→ <code>docker rmi</code>（删除）；</li>
<li><strong>容器操作</strong>：<code>docker run -it</code>（创建启动）→ <code>docker ps</code>（查看状态）→ <code>docker exec -it</code>（进入容器）→ <code>docker start/stop</code>（启停）→ <code>docker rm</code>（删除）；</li>
<li><strong>运维操作</strong>：<code>docker logs</code>（查日志）→ <code>docker system prune</code>（清理垃圾）。</li>
</ol>
<p>关键提醒：针对该镜像（Alpine 系统），创建容器时必须指定<code>/bin/sh</code>（而非<code>/bin/bash</code>），且加<code>-it</code>参数，否则容器会启动后立刻退出。</p>
<h3 id="使用powershell">使用powershell</h3>
<h4 id="切换目录的正确写法">切换目录的正确写法</h4>
<p>如果要切换到 C 盘根目录，正确命令有两种：</p>
<p><strong>powershell</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 方法1：完整路径（最规范，推荐）</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd </span><span class="n">C:</span><span class="p">\</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 方法2：简写（PowerShell支持的盘符切换方式）</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd </span><span class="n">C:</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>其他常用的目录切换规范：</p>
<p>powershell</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 切换到上级目录</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd </span><span class="p">..</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 切换到用户主目录（比如C:\Users\你的用户名）</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd </span><span class="p">~</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 切换到带空格的目录（必须用引号包裹）</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd </span><span class="s2">&#34;C:\Program Files&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 切换到指定子目录（比如C盘下的Temp文件夹）</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd </span><span class="n">C:</span><span class="p">\</span><span class="n">Temp</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="powershell-命令的通用规范">PowerShell 命令的通用规范</h4>
<ul>
<li><strong>路径区分大小写吗？</strong>：不区分（Windows 系统特性），<code>cd C:\temp</code> 和 <code>cd C:\Temp</code> 效果一样。</li>
<li><strong>特殊字符处理</strong>：路径含空格 / 特殊符号（如<code>&amp;</code>、<code>(</code>）时，必须用双引号<code>&quot;&quot;</code>包裹。</li>
<li><strong>命令别名</strong>：PowerShell 兼容部分 DOS/CMD 别名（比如<code>cd</code>等价于<code>Set-Location</code>，<code>dir</code>等价于<code>Get-ChildItem</code>），但推荐优先用完整命令（更易读）。</li>
<li><strong>执行脚本 / 程序</strong>：当前目录下的脚本需要加<code>./</code>，比如<code>./test.ps1</code>（直接写<code>test.ps1</code>会报错）。</li>
</ul>
<h4 id="推荐的-powershell-学习--参考网站">推荐的 PowerShell 学习 / 参考网站</h4>
<ol>
<li>
<p><strong>微软官方文档（最权威）</strong></p>
<ul>
<li>地址：<a href="https://learn.microsoft.com/zh-cn/powershell/">https://learn.microsoft.com/zh-cn/powershell/</a></li>
<li>优势：全中文、覆盖基础到高级、示例丰富，包含命令参考、语法规范、最佳实践，是新手入门的首选。</li>
</ul>
</li>
<li>
<p><strong>PowerShell Gallery（命令 / 模块库）</strong></p>
<ul>
<li>地址：<a href="https://www.powershellgallery.com/">https://www.powershellgallery.com/</a></li>
<li>优势：可以查找官方 / 社区维护的 PowerShell 模块，附带使用示例，解决实际场景问题（比如文件处理、系统管理）。</li>
</ul>
</li>
<li>
<p><strong>SS64（速查手册）</strong></p>
<ul>
<li>地址：<a href="https://ss64.com/ps/">https://ss64.com/ps/</a></li>
<li>优势：按字母排序的 PowerShell 命令速查表，每个命令都有简洁的语法、示例，适合快速查阅（支持中英文）。</li>
</ul>
</li>
<li>
<p><strong>GitHub PowerShell 社区</strong></p>
<ul>
<li>地址：<a href="https://github.com/PowerShell/PowerShell">https://github.com/PowerShell/PowerShell</a></li>
<li>优势：查看 PowerShell 源码、提问题、看社区贡献的示例脚本，适合进阶学习。</li>
</ul>
</li>
</ol>
<h2 id="认识编译实践中用到的编译器中间表示-koopa-ir">认识编译实践中用到的编译器中间表示: Koopa IR.</h2>
<h3 id="运行hello-world">运行hello world</h3>
<h4 id="具体环境">具体环境</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># cat /etc/os-release</span>
</span></span><span class="line"><span class="cl"><span class="nv">PRETTY_NAME</span><span class="o">=</span><span class="s2">&#34;Ubuntu 24.04.3 LTS&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">NAME</span><span class="o">=</span><span class="s2">&#34;Ubuntu&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">VERSION_ID</span><span class="o">=</span><span class="s2">&#34;24.04&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">VERSION</span><span class="o">=</span><span class="s2">&#34;24.04.3 LTS (Noble Numbat)&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">VERSION_CODENAME</span><span class="o">=</span>noble
</span></span><span class="line"><span class="cl"><span class="nv">ID</span><span class="o">=</span>ubuntu
</span></span><span class="line"><span class="cl"><span class="nv">ID_LIKE</span><span class="o">=</span>debian
</span></span><span class="line"><span class="cl"><span class="nv">HOME_URL</span><span class="o">=</span><span class="s2">&#34;https://www.ubuntu.com/&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">SUPPORT_URL</span><span class="o">=</span><span class="s2">&#34;https://help.ubuntu.com/&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">BUG_REPORT_URL</span><span class="o">=</span><span class="s2">&#34;https://bugs.launchpad.net/ubuntu/&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">PRIVACY_POLICY_URL</span><span class="o">=</span><span class="s2">&#34;https://www.ubuntu.com/legal/terms-and-policies/privacy-policy&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">UBUNTU_CODENAME</span><span class="o">=</span>noble
</span></span><span class="line"><span class="cl"><span class="nv">LOGO</span><span class="o">=</span>ubuntu-logo
</span></span></code></pre></td></tr></table>
</div>
</div><table>
	<thead>
			<tr>
					<th>参数名</th>
					<th>具体值</th>
					<th>含义解释</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>PRETTY_NAME</code></td>
					<td>&ldquo;Ubuntu 24.04.3 LTS&rdquo;</td>
					<td><strong>友好显示名称</strong>：最直观的系统版本描述，告诉你这是 Ubuntu 24.04.3 长期支持版（LTS）</td>
			</tr>
			<tr>
					<td><code>NAME</code></td>
					<td>&ldquo;Ubuntu&rdquo;</td>
					<td><strong>系统发行版名称</strong>：明确这是 Ubuntu 系统（而非 Debian/CentOS 等）</td>
			</tr>
			<tr>
					<td><code>VERSION_ID</code></td>
					<td>&ldquo;24.04&rdquo;</td>
					<td><strong>核心版本号</strong>：Ubuntu 的版本号规则是「年份。月份」，24.04 代表 2024 年 4 月发布的版本，这是系统的核心标识，安装软件时主要参考这个</td>
			</tr>
			<tr>
					<td><code>VERSION</code></td>
					<td>&ldquo;24.04.3 LTS (Noble Numbat)&rdquo;</td>
					<td><strong>完整版本信息</strong>： \- 24.04.3：24.04 版本的第 3 次更新维护版 \- LTS：Long Term Support（长期支持版），Ubuntu LTS 版本会提供 5 年的安全更新和维护 \- Noble Numbat：该版本的开发代号（每代 Ubuntu 都有动物代号）</td>
			</tr>
			<tr>
					<td><code>VERSION_CODENAME</code></td>
					<td>noble</td>
					<td><strong>版本代号（简写）</strong>：对应上面的 Noble Numbat，简写为 noble，在配置软件源、安装特定版本软件时可能会用到</td>
			</tr>
			<tr>
					<td><code>ID</code></td>
					<td>ubuntu</td>
					<td><strong>系统唯一标识</strong>：标准的系统 ID，脚本 / 程序中会用这个判断系统类型（比如判断是否是 Ubuntu）</td>
			</tr>
			<tr>
					<td><code>ID_LIKE</code></td>
					<td>debian</td>
					<td><strong>亲缘系统</strong>：Ubuntu 基于 Debian 开发，所以包管理器（apt）、系统架构和 Debian 一致，这也是为什么 Ubuntu 能用 Debian 的很多软件源</td>
			</tr>
			<tr>
					<td><code>HOME_URL</code></td>
					<td><a href="https://www.ubuntu.com/">https://www.ubuntu.com/</a></td>
					<td>Ubuntu 官方主页地址</td>
			</tr>
			<tr>
					<td><code>SUPPORT_URL</code></td>
					<td><a href="https://help.ubuntu.com/">https://help.ubuntu.com/</a></td>
					<td>Ubuntu 官方帮助文档地址</td>
			</tr>
			<tr>
					<td><code>BUG_REPORT_URL</code></td>
					<td><a href="https://bugs.launchpad.net/ubuntu/">https://bugs.launchpad.net/ubuntu/</a></td>
					<td>Ubuntu 官方 bug 反馈平台地址</td>
			</tr>
			<tr>
					<td><code>PRIVACY_POLICY_URL</code></td>
					<td><a href="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy">https://www.ubuntu.com/legal/terms-and-policies/privacy-policy</a></td>
					<td>Ubuntu 隐私政策地址</td>
			</tr>
			<tr>
					<td><code>UBUNTU_CODENAME</code></td>
					<td>noble</td>
					<td><strong>Ubuntu 专属版本代号</strong>：和 VERSION\_CODENAME 一致，是 Ubuntu 特有的标识，作用相同</td>
			</tr>
			<tr>
					<td><code>LOGO</code></td>
					<td>ubuntu-logo</td>
					<td>系统默认 logo 标识（主要用于图形界面，容器中一般用不到）</td>
			</tr>
	</tbody>
</table>
<h4 id="步骤">步骤</h4>
<p>把一个 Koopa IR 程序保存在了文件 hello.koopa 中
hello.koopa :</p>
<pre tabindex="0"><code class="language-koopa" data-lang="koopa">// SysY 中的 `putch` 函数的声明.
decl @putch(i32)

// 一个用来输出字符串 (其实是整数数组) 的函数.
// 函数会扫描输入的数组, 将数组中的整数视作 ASCII 码, 并作为字符输出到屏幕上,
// 遇到 0 时停止扫描.
fun @putstr(@arr: *i32) {
%entry:
  jump %loop_entry(@arr)

// Koopa IR 采用基本块参数代替 SSA 形式中的 Phi 函数.
// 当然这部分内容并不在实践要求的必选内容之中, 你无需过分关注.
%loop_entry(%ptr: *i32):
  %cur = load %ptr
  br %cur, %loop_body, %end

%loop_body:
  call @putch(%cur)
  %next = getptr %ptr, 1
  jump %loop_entry(%next)

%end:
  ret
}

// 字符串 &#34;Hello, world!\n\0&#34;.
global @str = alloc [i32, 15], {
  72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33, 10, 0
}

// `main` 函数, 程序的入口.
fun @main(): i32 {
%entry:
  %str = getelemptr @str, 0
  call @putstr(%str)
  ret 0
}
</code></pre><p>运行</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">koopac hello.koopa <span class="p">|</span> llc --filetype<span class="o">=</span>obj -o hello.o
</span></span><span class="line"><span class="cl">clang hello.o -L<span class="nv">$CDE_LIBRARY_PATH</span>/native -lsysy -o hello
</span></span><span class="line"><span class="cl">./hello
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="什么是-koopa-ir">什么是 Koopa IR</h3>
<blockquote>
<p>Koopa IR 是一种专为北京大学编译原理课程实践设计的教学用的中间表示 (IR), 它在设计上类似 LLVM IR, 但简化了很多内容, 方便大家上手和理解.</p>
<p>同时, 我们为 Koopa IR 开发了对应的框架 (koopa 和 libkoopa), 大家在使用 C/C++/Rust 编程时, 可以直接调用框架的接口, 实现 Koopa IR 的生成/解析/转换.</p>
<p>Koopa IR 是一种强类型的 IR, IR 中的所有值 (Value) 和函数 (Function) 都具备类型 (Type). 这种设计避免了一些 IR 定义上的模糊之处, 例如之前的教学用 IR 完全不区分整数变量和数组变量, 很容易出现混淆; 同时可以在生成 IR 之前就确定 IR 中存在的部分问题, 例如将任意整数作为内存地址并向其中存储数据.</p>
<p>Koopa IR 中, 基本块 (basic block) 必须是显式定义的. 即, 在描述函数内的指令时, 你必须把指令按照基本块分组, 每个基本块结尾的指令只能是分支/跳转/函数返回指令之一. 在 IR 的数据结构表示上, 指令也会被按照基本块分类. 这很大程度上方便了 IR 的优化, 因为许多优化算法都是在基本块的基础上对程序进行分析/变换的.</p>
<p>Koopa IR 还是一种 SSA 形式的 IR. 虽然这部分内容在课程实践中并非必须掌握, 但考虑到有些同学可能希望在课程实践的要求上, 做出一个更完备, 更强大的编译器, 我们将 Koopa IR 设计成了同时兼容非 SSA 形式和 SSA 形式的样子. 基于 SSA 形式下的 Koopa IR, 你可以开展更多复杂且有效的编译优化.</p>
</blockquote>
<blockquote>
<p>&mdash; 引自 <a href="https://pku-minic.github.io/online-doc/#/lv0-env-config/koopa?id=%e6%9c%ac%e5%9c%b0%e8%bf%90%e8%a1%8c-koopa-ir">北大编译实践在线文档</a></p>
</blockquote>
<ul>
<li>
<p>LLVM IR（Intermediate Representation）: 是LLVM编译器架构中的一种中间表示形式，它充当编译器前端和后端之间的桥梁。LLVM IR设计为与特定目标机器无关，使得编译器能够支持多种源语言并为多种目标生成代码。LLVM IR在编译过程中起到至关重要的作用，因为它是大多数目标无关优化发生的地方。</p>
</li>
<li>
<p>SSA形式（Static Single Assignment Form）: 是一种程序表示形式。SSA形式要求每个变量在程序中只能被赋值一次，这意味着每个变量的定义（def）和使用（use）关系非常明确。变量的生命周期从第一次定义到最后一次使用，这种清晰的结构使得编译器能够更容易地进行数据流分析和优化。</p>
</li>
</ul>
<h3 id="认识编译实践中开发的编译器的目标架构-risc-v">认识编译实践中开发的编译器的目标架构: RISC-V.</h3>
<blockquote>
<p>在编译实践中, 你将开发一个生成 RISC-V 汇编的编译器. 那么首先, 什么是 RISC-V?</p>
<p>RISC-V, 读作 “risk-five”, 是由加州大学伯克利分校设计并推广的第五代 RISC 指令系统体系结构 (ISA). RISC-V 没有任何历史包袱, 设计简洁, 高效低能耗, 且高度模块化——最主要的, 它还是一款完全开源的 ISA.</p>
<p>RISC-V 的指令系统由基础指令系统 (base instruction set) 和指令系统扩展 (extension) 构成. 每个 RISC-V 处理器必须实现基础指令系统, 同时可以支持若干扩展. 常用的基础指令系统有两种:</p>
<ul>
<li><code>RV32I</code>: 32 位整数指令系统.</li>
<li><code>RV64I</code>: 64 位整数指令系统. 兼容 <code>RV32I</code>.</li>
</ul>
<p>常用的标准指令系统扩展包括:</p>
<ul>
<li><code>M</code> 扩展: 包括乘法和除法相关的指令.</li>
<li><code>A</code> 扩展: 包括原子内存操作相关的指令.</li>
<li><code>F</code> 扩展: 包括单精度浮点操作相关的指令.</li>
<li><code>D</code> 扩展: 包括双精度浮点操作相关的指令.</li>
<li><code>C</code> 扩展: 包括常用指令的 16 位宽度的压缩版本.</li>
</ul>
<p>我们通常使用 <code>RV32/64I</code> + 扩展名称的方式来描述某个处理器/平台支持的 RISC-V 指令系统类型, 例如 <code>RV32IMA</code> 代表这个处理器是一个 32 位的, 支持 <code>M</code> 和 <code>A</code> 扩展的 RISC-V 处理器.</p>
<p>在课程实践中, 你的编译器将生成 <code>RV32IM</code> 范围内的 RISC-V 汇编.</p>
</blockquote>
<blockquote>
<p>&mdash; 引自 <a href="https://pku-minic.github.io/online-doc/#/lv0-env-config/riscv">北大编译实践在线文档</a></p>
</blockquote>
<hr>
<p><strong>参考</strong></p>
<ul>
<li><a href="https://pku-minic.github.io/online-doc/#/">北大编译实践在线文档</a></li>
<li><a href="https://docs.docker.top/manuals/index.htm">docker文档</a></li>
<li><a href="https://www.doubao.com/chat">doubao</a></li>
</ul>
]]></content:encoded></item></channel></rss>