新闻详情

新闻详情

首页 / 资讯中心 / 详情

Sentaurus TCAD自学笔记:Scheme脚本语法速查与避坑指南

发布时间:2026/10/2 11:28:55来源:尧图网络
Sentaurus TCAD自学笔记:Scheme脚本语法速查与避坑指南
最近在捣鼓Sentaurus TCAD发现很多人包括我自己第一步不是被半导体物理难住而是卡在它的脚本语言上。进去以后满屏的括号改了参数一跑就报错看半天不知道哪里出了问题。这个语言就是Scheme一门有几十年历史的函数式编程语言也是Sentaurus TCAD里做结构定义、参数扫描、数据提取时绕不开的工具。这篇东西我想把自己学习Sentaurus TCAD过程中Scheme这块的笔记整理出来围绕“到底哪些语法够用、什么时候必须用、怎么写才不容易翻车”这几个最实际的问题展开。不是从头教Scheme而是站在“干完Sentaurus仿真活”的角度把最常见、最实用的部分拎出来讲清楚配上能直接改用的脚本例子。刚接触Sentaurus、被scheme文件折磨得头疼的人以及想从纯GUI操作转向自动化批处理的人可以直接拿这篇做个索引和避坑手册。1. 一上来先搞清楚Sentaurus里Scheme到底管哪摊事1.1 它并不是“可选装”的编程语言Sentaurus TCAD不是一个单体软件而是一整套工具链。常见的流程是用Sentaurus Structure Editorsde画结构、定义掺杂用Sentaurus Devicesdevice跑电学特性再用Sentaurus Visualsvisual做数据提取和画图。这套流程里每一步都留了脚本接口而脚本语言主要就是Scheme部分场景也支持内置的Tcl或Python但看官方例子和网上的教学资料最主流、文档最全的还是Scheme。sde里的命令文件通常是.scm后缀内容就是一段一段带括号的Scheme表达式用来告诉软件怎么生成几何区域、怎么加电极、怎么设置掺杂。svisual里的数据提取脚本同样也用Scheme比如画IV曲线、算阈值电压、从截面数据里提取峰值掺杂浓度甚至是做多组结构间的数据对比这些都离不开它。所以Scheme在这条链路里的角色更像“胶水层”。它不是用来写物理模型的而是用来控制其它模块的输入和输出把一次复杂仿真做成一串可重复的流程。换句话说要真正用上Sentaurus的自动化、批量、参数化能力Scheme这关躲不掉。1.2 为什么Sentaurus偏偏选Scheme不少刚入手的人会吐槽工业仿真软件为什么不直接用Python当脚本语言这个问题官方没有专门解释过但从软件发展历史和实际使用体验上能看出一些原因。Scheme是Lisp家族的一员语法极其简单核心只有“表达式”和“列表”两种概念。它的代码本身就是一个嵌套列表嵌套列表又天然适合表达带层级关系的操作序列这和TCAD里“定义结构→设置掺杂→加入电极”这样有层级、有先后顺序的操作模型刚好合拍。换一种说法在Scheme里写一条带参数的“命令”跟在sde的GUI菜单里点一次操作很像都是前括号起、后括号收、参数排在里面。这个特性让同一个操作既能在GUI里手动完成也能原样记录、回放成脚本降低了两者之间的“翻译”成本。另外Lisp系语言在数据处理上也很灵活特别是list和vector的组合操作做掺杂浓度扫描、参数枚举这类批量任务非常顺手。虽然现在Python生态更强但Sentaurus的历史包袱和内部架构决定了Scheme在它体系里的地位短期内不会变。1.3 思维转变从“命令式”切到“函数式”大多数人学Scheme卡住不是语法难而是思维方式转不过来。写惯了C、Python这类命令式语言思维惯性是“先做A再做B然后C”每一步都改变某个变量或状态。Scheme虽然也有顺序执行的写法但它的核心思路是“表达式求值”整个脚本就是一个大表达式一层一层往里套每一层调用一个函数返回一个值最终组合出想要的结果。举个生活化的例子。命令式语言像写菜谱“拿锅倒油放葱翻炒盛出。”每一步都操作同一个锅锅里的内容一直在变。Scheme更像定义“食材变换规则”有一个函数叫fry你喂给它“豆腐和葱”它返回“炒好的菜”中间过程不暴露在外面。这种思路在定义器件结构时非常有优势因为你可以把“生成一个MOS结构”定义成一个函数传不同的沟道长度、氧化层厚度进去它返回不同的结构天然支持参数化。我刚开始从Python切过来也有阵子很不适应尤其是想用循环的时候总会下意识找for或while。后来发现在大多数TCAD场景里根本没必要写传统循环一条map或for-each就够而且表达得更清楚数据也好管理。这个转换是学习曲线里最陡的一段迈过去之后回头看反而觉得它的简洁性是种享受。2. 入门第一课读懂并写出第一段Sentaurus Scheme脚本2.1 只学真正会用到的语法不要一上来就去啃《The Little Schemer》之类的经典教材内容太偏理论很多概念如continuation、call/cc在Sentaurus脚本里一辈子都用不上。我把自己在Sentaurus里用到的Scheme语法整理成一个最小集先学会这些足够应付绝大多数场景。第一个是基本表达式和注释。表达式就是(函数 参数 ...)这种形式注释用分号;分号后面到行尾会被忽略。字符串用双引号数字不需要引号。下面是一段最简单的例子; 定义一个变量表示衬底掺杂浓度 (define n-sub 1e16) ; 打印到log窗口 (printf 衬底掺杂浓度 %e cm-3\n n-sub)第二是define和lambda。define用来定义变量也可以用来“给函数起名字”。lambda用来创建一个匿名函数相当于Python里的lambda。区别是Scheme里的lambda更常用很多地方直接把函数当参数传来传去。; 定义一个函数计算ln(浓度)再乘以一个系数 (define (calc-factor conc) (* (log conc) 0.025)) ; 也可以写成lambda形式 (define calc-factor (lambda (conc) (* (log conc) 0.025))) ; 调用 (printf factor %f\n (calc-factor 1e17))第三是条件分支。最常用的是if和cond。if适合一个条件两个分支的情况cond适合多条件分支比嵌套一堆if好看得多。(if ( doping 1e17) (printf 高掺杂区\n) (printf 低掺杂区\n)) (cond (( doping 1e15) (printf 轻掺杂\n)) (( doping 1e18) (printf 中等掺杂\n)) (else (printf 重掺杂\n)))第四是列表和vector。列表是Lisp系语言的看家本领但在Sentaurus脚本的实际使用里vector更常用因为要处理数值型扫描数据vector可以直接按索引访问性能也好得多。; 创建一个vector (define v (vector 1 2 3 4 5)) ; 访问第几个元素下标从0开始 (printf ~a\n (vector-ref v 2)) ; 输出3 ; 获取长度 (printf 长度~a\n (vector-length v))第五是循环相关。Scheme里常规写法确实不是for循环而是递归或for-each。在Sentaurus脚本里最常用的是for-each它接收一个函数和一个列表对列表里的每个元素依次调用该函数相当于“对每个元素做同一件事”。; 对1到5每个数字打印它的平方 (for-each (lambda (i) (printf ~a的平方是~a\n i (* i i))) (1 2 3 4 5))这五个语法块基本覆盖了90%的Sentaurus Scheme脚本场景。剩下的边角语法如字符串拼接、文件名处理、正则表达式用到时再查不必在入门阶段死记。2.2 读懂Sentaurus自带例子文件掌握了基础语法后最快的进阶方式不是看书而是“读例子”。Sentaurus安装目录里有大量示例工程路径一般在Sentaurus安装目录/tcad/.../sde_examples或.../demo下。这些例子文件后缀不同有的是.scm有的是.sde内容有长有短。读这些文件时我建议三步走。第一步只读“结构骨架”把最外层调用了哪些函数找出来比如sdegeo:create-rectangle、sdedr:define-constant-profile、sde:add-metal-contact这些先知道这个脚本大概画了哪些东西。第二步再细看参数搞清楚每个函数都接收了什么参数哪些是坐标、哪些是材料名、哪些是浓度值。第三步才去追“哪些变量会影响最终结构”这样就能把脚本真正变成自己手里的可调参数模板。这里有个很典型的细节sdegeo:create-rectangle用来创建矩形区域参数通常是坐标点和区域名。sdedr:define-constant-profile用来定义恒定掺杂它需要一个名字、一种杂质类型、一个浓度值和作用范围。这些函数名很有规律基本是“模块名:函数名”的格式很像命名空间。读多了以后看到sdedr:开头的函数就知道它跟掺杂定义有关看到sdegeo:开头的函数就知道它跟几何结构有关。这种规律能帮你快速定位问题比如某个报错发生在掺杂阶段那就优先查带sdedr前缀的代码段。2.3 第一段能跑的实用脚本参数化生成结构我建议入门后就逼自己写一个实用脚本把结构参数定义成变量方便后续批量替换。下面这个例子生成一组宽度不同的矩形区域类似简化版的MOS沟道为了演示define和基本的调用方式而写正常运行需要你在sde的Scheme命令行里执行或者是放在一个后缀为scm的命令文件里通过File→Load Command File加载。; 参数区改这里就能快速调整结构 (define (gen-structure w) ; 先删除旧区域避免重复生成 (sdegeo:delete-region (list R.Chan)) ; 创建一个矩形区域宽w厚0.02单位后面再解释 (sdegeo:create-rectangle (position 0.0 0.0 0.0) (position w 0.02 0.0) Silicon R.Chan) (printf 已生成宽度为 ~a 的沟道区域\n w)) ; 可以先手动调用验证效果 (gen-structure 0.5)这里要注意代码里sdegeo:delete-region的参数是区域名组成的列表如果区域不存在会告警。position是三维坐标点。运行后界面里应该能看到一个矩形区域宽度可以通过调用gen-structure时传的参数控制。这就是最简单的参数化思路后续可以扩展成包含衬底、源漏、栅氧、电极的完整结构生成脚本只不过里面的几何操作和掺杂设置会多很多。3. 实操从“能跑”到“自动化批量仿真”3.1 环境准备在哪写、怎么跑Sentaurus里写Scheme有三种常见方式。第一种是直接在sde的GUI下方面板里逐行敲适合临时验证某个表达式对不对。第二种是把代码写进.scm文件用File→Load Command File加载适合结构定义这种较长脚本。第三种是在终端里以命令行模式启动sde传命令文件路径适合批量流程和无人值守仿真。我自己的习惯是第二种配第三种结合用开发调试时用GUI加载跑批量时写个shell脚本调sde命令行。实际中命令行参数会因版本不同有差异建议先看一眼当前版本的用户手册里“Structure Editor Command Line”章节再写启动命令别照抄网上旧教程版本对不上会报莫名奇妙的错。初次使用时还要确认下路径问题。sde在脚本里写的所有坐标都是基于当前工作区如果你用GUI手工改过结构再加载另存的文件可能会因为单位制或轴方向不一致导致结构偏移。遇到这类问题先看状态栏坐标显示确认当前坐标单位是微米还是纳米。3.2 批量生成不同结构一次跑完多组参数自动化最典型的应用场景是扫参。比如研究沟道长度Lg对阈值电压的影响手工一个一个建结构、跑仿真效率极低写个Scheme脚本在sde里把结构按一组Lg值循环生成配合后面sdevice做批量求解可以把整轮仿真时间从几天缩到几小时。下面这段代码演示如何批量生成多个矩形区域区分的办法是给每个区域起不同的名字。这个例子为了展示循环和名字拼接真实项目中你会把每个区域单独放或者配合变量定义电极。; 批量生成三个不同宽度的沟道区域 (for-each (lambda (w i) (let ((rname (string-append R.Chan (number-string i)))) (sdegeo:create-rectangle (position 0.0 (* 0.03 i) 0.0) (position w ( (* 0.03 i) 0.02) 0.0) Silicon rname) (printf 生成区域 ~a宽度 ~a\n rname w))) (0.3 0.5 0.7) (1 2 3))这里用到let临时定义变量string-append拼接字符串number-string把数字转成字符串。这三个都是很常用的辅助工具。for-each可以同时遍历多个列表比如这里同时遍历宽度列表和编号列表这种写法在处理多组参数时特别方便不用去维护一个计数器变量。3.3 与sdevice协同最简单的IV数据自动提取到svisual阶段Scheme还能做数据提取和输出。典型需求是跑完一个器件在不同栅压下的一系列Id-Vg特性然后批量提取每个栅压对应的饱和电流。svisual的数据模型里你可以先通过菜单或命令把仿真结果载入到Prober然后对Prober里的曲线对象做数学运算。下面是一段在SVisual里用Scheme对提取到的电流数据做对数变换并输出的示例代码具体API名称在不同版本有差异重点看思路; 假设已经通过SVisual菜单操作把某条Id-Vg曲线载入到prober (define curve (prober:get-data 1)) ; 提取x和y轴数据 (define vg (data:get-x curve)) (define id (data:get-y curve)) ; 计算log(Id) (define log-id (map (lambda (v) (log v)) id)) ; 把结果写到文件 (define out (open-output-file id_log.txt)) (for-each (lambda (x y) (format out ~f ~f\n x y)) vg log-id) (close-output-port out)这里用到的map和for-each是很典型的函数式数据处理方式。map对列表里每个元素做变换返回一个新列表for-each只遍历不保留结果多用于输出。如果数据量特别大把vector先转成list再map性能会差但SVisual里曲线数据规模一般不大速度问题影响不大。真要处理大规模数据可以用vector-map一类的函数效率高很多。3.4 提高脚本复用度把公共函数独立出来写了几个脚本之后你会发现不少代码是重复的比如“根据名字找区域”“根据坐标加点”“导出数据到文件”。这些公共部分建议单独存成一个util.scm放在固定目录里每次新写脚本时用load函数加载进来只写差异部分。; util.scm 内容示例 (define (print-line . args) (apply printf args) (newline)) ; 主脚本里加载工具文件 (load ~/tcad_lib/util.scm) (print-line 宽 ~a 长 ~a 0.5 1.0)这个做法的好处是一旦你优化了某个公共函数所有依赖它的脚本都能受益不用一处一处去改。我一开始也嫌麻烦觉得复制粘贴来得快等脚本数量涨到两位数就开始后悔了——改一处漏一处定位半天。所以建议从刚开始学就养成模块化的习惯。4. 常见报错和排查技巧实录4.1 括号匹配错误看得人脑壳疼Scheme的报错信息通常不会像Python那样精确到行列号只会说“unexpected right parenthesis”或者“unexpected end-of-file”。这种错误十有八九是括号数量不匹配。排查方法我推荐三步第一把代码在编辑器里打开开启括号高亮功能Vim里可以配合Rainbow Parentheses插件VS Code有Bracket Pair Colorizer一眼就能看出哪里颜色对不上。第二把出问题的函数体单独选中在后括号旁边停一下看编辑器是否显示匹配到了正确的前括号。第三实在找不到就分段注释定位把后半段注释掉看前半段能不能跑通再逐步缩小范围。这里特别提醒一点if的分支和函数调用一样每个括号都要成对。写的时候注意区分“函数调用的括号”和“分组的括号”前者前面有函数名后者前面是什么都没有仅仅是区分优先级。初学者最怕的写法是(if ( a b) (printf a) (printf b))里少了个括号软件会把你后面的表达式当成if的一个分支表现出的现象就是“明明条件为真却执行了两个分支”或反过来的怪事。4.2 “变量未定义”和“函数未定义”这类报错通常是reference to undefined identifier。最常见原因是变量名拼错或大小写不一致。Scheme区分大小写Vg、vg、vG是三个完全不同的名字。其次是作用域问题你在某个lambda或let内部用了外部变量但外部变量定义在它后面Scheme又是顺序求值执行到lambda内部时外部变量还没被定义就会报undefined。解决办法是“先定义后使用”。在脚本最开始把所有参数集中定义好后面再写函数和调用。交叉引用多的场景可以把核心参数放进一个let*或begin块里保证按依赖顺序定义。4.3 类型不匹配数字当成字符串用了报错信息可能是expects argument of type number或vector-ref: expects a vector。这类错误的原因很直接传参类型和函数期望不一致。常见的坑是number-string忘了转直接把数字拿去拼字符串或者从数据文件里读出来的一串字符忘了用string-number转成数字就做数学运算。我用过一个办法能明显减少这类问题“先打印后计算”。凡是数据来源比较复杂的地方先printf打印出来确认类型和值对不对再做下一步操作。看似多条打印语句实际帮你节省不少调试时间。4.4 Sentaurus特定API的坑几何区域重复定义还有一类报错不是Scheme语法层面的而是Sentaurus模块自身报的。比如在sde里重复定义同名区域软件会提示“region already exists”或者干脆没有任何提示但后面的掺杂、接触定义全乱套。这时候基本可以断定是脚本里define-*类的操作重复执行了。建议在写脚本时给所有区域和profile起名时加个生成策略。最粗暴也最有效的策略是每次跑脚本前先把所有区域删干净或者用带时间戳、参数值后缀的名字保证每次执行都不会撞名。之前看不少官方示例脚本直接写死名字你自己跑第二遍就会出事这就是示例脚本“一次性”的特点容易误导新人。下面把常见的报错整理成一个速查表方便后面直接回来看。报错信息关键词可能原因排查手段unexpected right parenthesis多写了右括号检查括号高亮分段注释unexpected end-of-file少写了右括号或注释没闭合检查末尾括号和分号注释undefined identifier变量未定义、拼写错误、作用域问题先定义后使用检查大小写expects argument of type number传参类型不正确打印参数值检查类型转换region already exists重复定义同名区域改名或先删除再生成no region with name ...引用了不存在的区域检查区域名是否拼写一致4.5 性能优化别把大列表当数组用跑了大量参数扫描后会明显感觉到脚本变慢。常见原因是拿list当数组用频繁list-ref按索引取元素。Scheme里list是链表结构按索引访问的时间复杂度是O(n)数据一多就慢。vector才是接近数组的结构按下标访问是O(1)。另一个性能瓶颈是递归写的循环。Scheme虽说支持尾递归优化但很多Sentaurus内置环境未必开了优化改用for-each、map或等价的vector迭代函数会好很多。实际工作中数据量过万之后差异能到几倍甚至几十倍。写之前想一想这组数据是要“逐个处理”还是“随机访问”处理方式会差别很大。5. 再往外走一步把Scheme用得更好的一些体会5.1 依赖手册但不盲信网上代码Sentaurus各版本封装了不少自定义函数这些函数很少在通用Scheme教程里出现网上能找到的示例也经常有版本差异。比如早期版本用sde:create-rectangle一些旧示例里也这么写但我查自己这个版本的手册发现有的函数已经改名或加了参数。我的习惯是拿到一个新函数先在当前版本的手册里搜一下函数名确认参数列表和返回值再去网上找示例。否则照着旧例子跑卡在莫名其妙的报错上浪费时间。关于手册我建议优先看安装目录里的PDF文档比如Sentaurus Structure Editor User Guide、Sentaurus Visual User Guide里面都有专门的“Commands”章节列出了所有用户可调用的Scheme函数和参数说明。读一遍确实枯燥但遇到问题再查效率极高。5.2 用“小而美”的脚本取代大而全的自动化刚开始我做自动化总想一步到位写一个脚本从结构生成、掺杂定义、电极设置全部搞定还要自动跑到sdevice、svisual一个命令跑完整个流程。后来发现这种大脚本调试成本太高一旦出错定位问题都很困难。后来改成“分阶段脚本”第一阶段只做结构生成单独跑通确认几何无误第二阶段加掺杂和接触跑一遍确认无误第三阶段再交给sdevice最后到svisual做数据提取。每个阶段之间用文件传数据比如sde生成结构后保存为结构文件sdevice读取它继续跑。这样每一步的输入输出都清晰可控出问题能定位到跟前。看似多写几个中间文件实际省下的调试时间是值得的。5.3 跟其它语言工具配合Scheme不是唯一选择虽然Sentaurus核心脚本是Scheme但在流程编排、批量管理、结果后处理上完全可以用Python来自动化。比如用Python生成一批Scheme脚本的参数文件、批量启动仿真、读取日志判断是否收敛、再把结果汇总成表格。Scheme负责“软件内部的事”Python负责“外部调度的事”各干各擅长的配合起来效率更高。我之前的一个实用玩法是用Python模板引擎生成Scheme脚本把要扫描的参数值填进去然后循环调用sde命令行跑出N组结构再用sdevice批量求解最后用Python分析输出数据。整个过程里Scheme脚本本身的逻辑一行没变变的只是参数。这种“参数与逻辑分离”的思路比在纯Scheme里用复杂的数据结构存参数更直观也更容易维护。5.4 我踩过的一个大坑单位制和坐标方向刚开始写sde脚本时一直没确认脚本里position的坐标单位是什么结果生成的器件结构尺寸明显不对。后来查手册才发现sde脚本里坐标默认单位是微米而不同版本的GUI可能显示纳米一旦没统一结构就会大出千倍或小千倍导致后续仿真结果完全不可信。现在我在每段脚本开头都加一段注释标注坐标单位和参考点同时写结构时尽量把坐标计算成基于某个变量的表达式这样就算后续要改整体尺寸也只改一个变量不会到处挖坑。单位制这件事说大不大说小不小但它属于“看得见摸不着”的坑等你在结果里发现异常再排查往往已经损失大量仿真机时。所以不管用什么工具第一件事都应该确认当前环境的单位设置。学习Sentaurus TCAD里的Scheme我的真实体会是它更像一门“方言”——基础语法很纯正不像Python那样有一大堆现代特性但只要你掌握了它的最小表达集再对照官方手册查缺补漏就能在TCAD流程里如鱼得水。别把它当成一门单独的编程语言去系统学那样容易陷进去把它当成控制Sentaurus的手柄摸清常用按钮在哪剩下的操作随用随查反而上手最快。最后分享一个小技巧写sde脚本时养成“打印关键参数”的习惯每定义完一个区域、一个掺杂、一个电极都用printf把名字和关键值打出来。这样跑完一次脚本log里就有了一份完整的过程记录哪里不对一眼就能看出来。这个习惯帮我省下了无数排查时间也让我对“脚本到底干了什么”始终心里有数。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Simulink液压系统建模:数值刚性、初始条件与变刚性问题排查指南 2026/10/2 13:20:54

Simulink液压系统建模:数值刚性、初始条件与变刚性问题排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
等保2.0接口加解密:RSA+AES混合加密与签名验签实现 2026/10/2 13:20:47

等保2.0接口加解密:RSA+AES混合加密与签名验签实现

2. 等保2.0接口加解密方案的整体设计思路2.1 为什么要用"RSAAES"混合加密,而不是只用一种很多刚接触接口安全的朋友会有一个直觉:既然要做加密,那直接上RSA不就行了?前端拿公钥加密,后端拿私钥解密&#xff…

阅读更多 →
西门子TSEND_C错误代码详解:STATUS排查与实战排错 2026/10/2 13:20:47

西门子TSEND_C错误代码详解:STATUS排查与实战排错

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
基于STM32的智能鸽子驯养系统实战设计 2026/10/2 13:20:47

基于STM32的智能鸽子驯养系统实战设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
STM32嵌入式系统在信鸽智能驯养中的闭环行为干预设计 2026/10/2 13:20:47

STM32嵌入式系统在信鸽智能驯养中的闭环行为干预设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
编译原理核心考点:龙书第二版习题答案与FIRST/FOLLOW/SLR解析 2026/10/2 13:20:47

编译原理核心考点:龙书第二版习题答案与FIRST/FOLLOW/SLR解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉