ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Buck 的 PSI 文法参考:Python 2.7 完整 BNF 文法及其在 ideabuck 解析器中的落地

Buck 的 PSI 文法参考:Python 2.7 完整 BNF 文法及其在 ideabuck 解析器中的落地 开发工具构建工具【免费下载链接】buckA fast build system that encourages the creation of small, reusable modules over a variety of platforms and languages.项目地址https://gitcode.com/gh_mirrors/bu/buck点击查看免费下载本文以 Buck 仓库 tools/psi-grammar/docs/Python2Grammar.md 为骨架完整解读 CPython 2.7 的正式文法BNF 产生式全集从三个起始符号、语句与复合语句结构到表达式的 12 级优先级层级、推导式与testlist_safe的历史细节同时结合仓库中 NextGenIdeabuckGrammar.bnf 与 Buck.bnf 的逐行注释说明 Buck 的 ideabuck 插件是如何把这份 Python 文法裁剪成 Starlark 子集、并经 JFlex Grammar-Kit 两遍生成变成可运行的 IntelliJ PSI 解析器的。读完后你既能独立读懂任意一份 BNF 文法也能理解一个 IDE 语法插件从文法文件到词法/语法分析器的完整工程链路。文档来龙去脉为什么 Buck 仓库里放着一份 Python 2.7 文法Python2Grammar.md 的第一行注明来源它取自 CPython 2.7 源码树中的Grammar/Grammar文件即 Python 2.7 解释器解析器所依据的正式文法。文件开头的注释还保留了 CPython 的原始告诫Changing the grammar specified in this file will most likely require corresponding changes in the parser module (../Modules/parsermodule.c) … You should also follow all the steps listed in PEP 306, How to Change Pythons Grammar也就是说这份文档不是孤立的笔记而是一份完整的语言规范级产物——它由 C 解析器直接驱动任何产生式的改动都必须同步修改解析模块。它被收录在 Buck 的tools/psi-grammar模块下是因为该模块正是 ideabuckBuck 的 IntelliJ 插件的词法/语法分析器所在。同目录下的 StarlarkLanguageOverview.md 与 StarlarkLanguageSpecification.md 分别摘录了 StarlarkBazel 构建语言Buck 的 BUCK/DEPS 文件语言与其同源的概述与形式规范而 Python2Grammar.md 则是这套文档体系中的基准参照系Buck 文件本质上是 StarlarkStarlark 在语法上又是 Python 2/3 的子集所以 Python 2.7 的完整文法就是裁剪出 Starlark 文法的全量母版。最能体现这一关系的是 NextGenIdeabuckGrammar.bnf 文件头的说明L17-L32// This file is not in use by Buck, and it is not the actual Buck grammar. // Instead, it is a prototype for a Buck grammar that more closely matches // the Python2 grammar, with specific exceptions for the Starlark language … // For reference, the full grammar of … appears below in comments, with // Bucks grammar interspersed throughout.即该文件把 Python2Grammar.md 的每一条产生式原文都以// [Python2]:注释形式逐行引在正文中再在其间穿插插值interspersedBuck 自己的对应产生式并在两者不一致处给出理由。下文第 28 节按原文档结构完整解读这份 Python 文法第 9 节再做逐条对照。文法记法约定如何阅读这份 BNF在逐条讲解之前先明确这份文法的记法BNF 的变体也是 Grammar-Kit.bnf文件的通用记法形如nonterminal: rhs的每一行是一条产生式左部是小写非终结符右部是终结符与非终结符的序列带单引号的串如def、是字面量终结符不带引号的大写标识符NAME、NUMBER、STRING、NEWLINE、INDENT、DEDENT、ENDMARKER是词法记号token由词法器产生[ x ]表示 x 可选0 或 1 次x*表示 0 次或多次x表示 1 次或多次( a | b )是选择词法层面还有一个关键约定INDENT/DEDENT是逻辑记号由缩进推导出来这与 Python 以缩进定块 的语法直接对应。Python2Grammar.md 全文约 144 行覆盖了 Python 2.7 的全部语法。下面按原文档的行文顺序完整给出各段产生式并逐段讲解。起始符号single_input、file_input 与 eval_input文法开篇定义了三个起始符号entry points对应三种输入场景single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE file_input: (NEWLINE | stmt)* ENDMARKER eval_input: testlist NEWLINE* ENDMARKERsingle_input交互式单行输入python 解释器的 REPL 模式。它要么是空行NEWLINE要么是一条简单语句要么是一条复合语句后跟换行——原文注释特意强调 compound_stmt in single_input is followed by extra NEWLINE因为交互式环境下复合语句需要用户敲一个空行来结束缩进块file_input从文件读入的模块即buck解析 BUCK 文件、Python 编译.py文件所走的路径——任意多条空行或语句以ENDMARKER文件结束记号收尾eval_inputeval()/input()的输入只允许一个测试列表testlist因为 eval 的对象是表达式而非语句。值得对照的一点是Buck 的实际文法 Buck.bnf 中对应的顶层产生式简化为buckFile :: statement*L130不再区分交互/文件两种模式——这与 BUCK 文件永远按文件编译的定位一致。函数定义、装饰器与参数列表decorator: dotted_name [ ( [arglist] ) ] NEWLINE decorators: decorator decorated: decorators (classdef | funcdef) funcdef: def NAME parameters : suite parameters: ( [varargslist] ) varargslist: ((fpdef [ test] ,)* (* NAME [, ** NAME] | ** NAME) | fpdef [ test] (, fpdef [ test])* [,]) fpdef: NAME | ( fplist ) fplist: fpdef (, fpdef)* [,]这段产生式刻画了def与装饰器的完整形态funcdef要求def关键字、一个NAME、参数表、冒号以及一个语句块suitevarargslist的三分支结构精确对应 Python 2.7 的参数规则前置若干具名参数fpdef [ test] ,每个可带任意表达式默认值或者* NAME [, ** NAME]*args可再跟**kwargs或者** NAME仅关键字展开fpdef: NAME | ( fplist )允许在参数表中写括号分组如def f((a, b)): ...这一特性在 Python 3 中已被移除——它本身就是 Python 2 的语法遗产。在 Starlark 侧的对照中这条产生式被大幅简化。Buck.bnf 中的对应写法是parameter_list :: [parameter (, parameter)* ,?] parameter :: ** identifier | * identifier | identifier [ simple_expression]NextGenIdeabuckGrammar.bnf 对此的注释引了 Starlark 规范StarSpec:107The grammar does not enforce the legal order of params and args——Starlark 有意不强制*args/**kwargs必须排最后于是文法上直接用更宽松的产生式。而 Python 2.7 原版的decorator/decorators/decorated三条产生式在 Buck 文法中则被整条删除注释为 No evidence that Starlark or Buck support decoratorsNextGenIdeabuckGrammar.bnf#L331。语句层级simple_stmt 与 small_stmtstmt: simple_stmt | compound_stmt simple_stmt: small_stmt (; small_stmt)* [;] NEWLINE small_stmt: (expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt)stmt是二选一简单语句或复合语句。simple_stmt允许用分号把多条small_stmt串在一行行尾还可再跟一个分号[;]以NEWLINE结束。small_stmt的 8 个分支覆盖了 Python 2 的全部简单语句逐条看赋值、增广赋值与 printexpr_stmt: testlist (augassign (yield_expr|testlist) | ( (yield_expr|testlist))*) augassign: ( | - | * | / | % | | | | ^ | | | ** | //) print_stmt: print ( [ test (, test)* [,] ] | test [ (, test) [,] ] )expr_stmt的testlist开头支持链式赋值a b 1与元组解包x, y y, x目标位置可以是yield_expr|testlist这为a b yield x这类写法留了语法空间是否合法由解释器进一步约束注释 For normal assignments, additional restrictions enforced by the interpreter 即指此augassign的 12 个算子与//地板除一起是 Python 2 的完整增广赋值集合Starlark 只保留了 - * / // %见 Buck.bnf#L171 的augment_assignmentprint_stmt把print当语句而非函数第二个分支 test支持向文件对象重定向print f, x——这是 Python 2 与 3 之间最著名的差异之一。del、pass 与流程控制del_stmt: del exprlist pass_stmt: pass flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt break_stmt: break continue_stmt: continue return_stmt: return [testlist] yield_stmt: yield_expr raise_stmt: raise [test [, test [, test]]]注意raise_stmt的三元形式raise test , test , test这是 Python 2 特有的raise Exc, value, tb三参异常抛出Python 3 改为raise exc from cause。yield_stmt独立成句配合文末的yield_expr: yield [testlist]。import、global 与 execimport_stmt: import_name | import_from import_name: import dotted_as_names import_from: (from (.* dotted_name | .) import (* | ( import_as_names ) | import_as_names)) import_as_name: NAME [as NAME] dotted_as_name: dotted_name [as NAME] import_as_names: import_as_name (, import_as_name)* [,] dotted_as_names: dotted_as_name (, dotted_as_name)* dotted_name: NAME (. NAME)* global_stmt: global NAME (, NAME)* exec_stmt: exec expr [in test [, test]] assert_stmt: assert test [, test]import_from的第一个选择项.* dotted_name | .精确刻画了相对导入from .mod import x点号串后跟模块名与from . import x纯点号串两种形态import *即from x import *exec_stmt是 Python 2 的exec语句Python 3 降格为函数[in test [, test]]对应exec code in globals, locals的执行环境参数assert_stmt的可选第二参数是断言失败信息assert cond, msg。Starlark 对照上述分支在 Buck.bnf 中被收敛为 8 个 simple 分支之一的新增条目load_call同时删除了print、del、import、global、exec、raise、yield。其中load是 Starlark 独有的模块加载语句其产生式Buck.bnf#L157-L167load_call :: load ( load_target_argument (, load_argument) (, load_argument)* [,] ) load_target_argument :: string load_argument :: [identifier ] string比import_from严格得多第一个参数必须是字符串字面量目标标签其余参数只能是sym orig_name形式的字符串映射不支持*、不支持*args/**kwargs。NextGenIdeabuckGrammar.bnf#L362-L367 的注释也明确the syntax of a load statement is much more restrictive than a normal argument_list。复合语句与 suite缩进如何进入文法compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated if_stmt: if test : suite (elif test : suite)* [else : suite] while_stmt: while test : suite [else : suite] for_stmt: for exprlist in testlist : suite [else : suite] try_stmt: (try : suite ((except_clause : suite) [else : suite] [finally : suite] | finally : suite)) with_stmt: with with_item (, with_item)* : suite with_item: test [as expr] # NB compile.c makes sure that the default except clause is last except_clause: except [test [(as | ,) test]] suite: simple_stmt | NEWLINE INDENT stmt DEDENT这段是 Python 块语法的核心逐点说明if_stmt的(elif test : suite)*把任意多 elif 表达为零次或多次重复for/while均支持可选的else块循环未被break打断时执行try_stmt是一个精巧的选择结构要么是至少一个except_clause可再跟else、finally要么是纯finally : suite。原文注释 NB compile.c makes sure that the default except clause is last 点出了一个重要事实裸except:不带异常类型的默认子句必须放在最后这一约束文法本身不表达由编译模块 compile.c 负责检查——这是文法 语义检查分工的典型例子with_item: test [as expr]让with open(f) as fh:中的绑定目标是一个通用表达式支持with a, b as x, c as y:的元组绑定suite是全文法中INDENT/DEDENT出现的地方要么同一行的单条简单语句要么是NEWLINE INDENT stmt DEDENT的缩进块。词法器把物理缩进翻译成这对逻辑记号文法层面就只剩普通的记号匹配了。Starlark 对照Buck.bnf#L183-L189 中compound_statement :: if_statement | for_statement | function_definition——while、try、with、classdef、decorated全部缺席for_statement也去掉了[else : suite]。NextGenIdeabuckGrammar.bnf#L434-L450 的注释逐条引用 Starlark 规范给出原因Starlark not supported: while, yield / try, raise, except, finally用fail代替致命错误for循环不支持 else 子句且for 语句不允许出现在顶层请折进函数。表达式层级十二级优先级与 test 的两种形态Python2Grammar.md 中最长的部分是表达式文法。它采用逐级升格的经典写法每引入一个低优先级算子就新增一层非终结符从条件表达式一路下沉到原子。全文如下test: or_test [if or_test else test] | lambdef or_test: and_test (or and_test)* and_test: not_test (and not_test)* not_test: not not_test | comparison comparison: expr (comp_op expr)* comp_op: ||||||!|in|not in|is|is not expr: xor_expr (| xor_expr)* xor_expr: and_expr (^ and_expr)* and_expr: shift_expr ( shift_expr)* shift_expr: arith_expr ((|) arith_expr)* arith_expr: term ((|-) term)* term: factor ((*|/|%|//) factor)* factor: (|-|~) factor | power power: atom trailer* [** factor]由此得到自低到高的完整优先级序同级左结合**右结合层级非终结符算子 / 形态结合性1lambdeflambda [varargslist] : test最低2test条件式X if C else Y右递归3or_testor左结合4and_testand左结合5not_testnot右递归一元6comparison ! in not in is is not可链式左结合7expr\|位或左结合8xor_expr^位异或左结合9and_expr位与左结合10shift_expr左结合11arith_expr-左结合12term*/%//左结合13factor一元-~右递归14power**右结合15atom/trailer字面量、括号、调用、下标、属性—几个值得停下来细读的点comparison: expr (comp_op expr)*表达链式比较1 x 5是合法的语义由求值器处理为1 x and x 5。这正是 Starlark 明确移除的特性——NextGenIdeabuckGrammar.bnf#L479-L485 将对照注释 Starlark does not support chained comparisons并把产生式改写成单次比较comparison_expression :: simple_expression [comparison_op simple_expression]同时删除is算子Starlark 要求用。test的双重身份test既可是一个条件三元表达式也可是一个lambdef。而条件式的 else 分支递归回test而非or_test这使a if c else b if d else e这类嵌套条件式在语法上成立且按右结合解析。power: atom trailer* [** factor]的右结合2 ** 3 ** 2解析为2 ** (3 ** 2) 512同时因为**直接挂在power层而一元算子在factor层-x ** 2解析为-(x ** 2)而非(-x) ** 2。这是该文法里层级顺序即语义的最典型例证。test以下的支撑产生式如下atom: (( [yield_expr|testlist_comp] ) | [ [listmaker] ] | { [dictorsetmaker] } | testlist1 | NAME | NUMBER | STRING) trailer: ( [arglist] ) | [ subscriptlist ] | . NAME subscriptlist: subscript (, subscript)* [,] subscript: . . . | test | [test] : [test] [sliceop] sliceop: : [test] exprlist: expr (, expr)* [,] testlist: test (, test)* [,] lambdef: lambda [varargslist] : testatom的五个分支即五类原子括号表达式含生成器与推导式、列表、字典/集合、反引号Python 2 独有的x强制 repr 语法Python 3 已移除、标识符/数字/字符串STRING注意是加号意味着相邻字符串字面量隐式拼接a b即ab。Starlark 禁止这种隐式拼接要求显式用见 NextGenIdeabuckGrammar.bnf#L68-L81 摘录的 Starlark 差异清单因此 Buck.bnf#L278 的atomic_expression中字符串只出现一次且 NextGenIdeabuckGrammar.bnf#L612-L619 为此单列了 8 个字符串记号单/双引号 × 普通/原始 × 单行/三引号的统一string产生式subscript的三个分支覆盖...Ellipsis、普通索引与切片[test] : [test] [sliceop]合起来支持a[:]、a[::2]、a[1:2:3]等全部切片形态power的trailer*允许obj().method[0]这类调用、下标、属性访问的任意交错序列。推导式、生成器与 testlist_safe 的历史细节listmaker: test ( list_for | (, test)* [,] ) testlist_comp: test ( comp_for | (, test)* [,] ) dictorsetmaker: ( (test : test (comp_for | (, test : test)* [,])) | (test (comp_for | (, test)* [,])) ) arglist: (argument ,)* (argument [,] |* test (, argument)* [, ** test] |** test) # The reason that keywords are test nodes instead of NAME is that using NAME # results in an ambiguity. ast.c makes sure its a NAME. argument: test [comp_for] | test test list_iter: list_for | list_if list_for: for exprlist in testlist_safe [list_iter] list_if: if old_test [list_iter] comp_iter: comp_for | comp_if comp_for: for exprlist in or_test [comp_iter] comp_if: if old_test [comp_iter] testlist1: test (, test)* # not used in grammar, but may appear in node passed from Parser to Compiler encoding_decl: NAME yield_expr: yield [testlist]listmaker与testlist_comp是同构的列表体开头一个test后面要么接推导/生成子句要么是普通逗号列表尾逗号可选。区别在于testlist_comp只出现在圆括号内(...)可以是生成器表达式而[...]内的推导式走listmakerdictorsetmaker用顶层选择区分字典推导test : test comp_for与集合推导test comp_for以及各自的普通字面量形态{a: 1, b: 2}与{1, 2}。Starlark 没有 set 也没有 float对应地 NextGenIdeabuckGrammar.bnf#L560-L564 将其裁剪为只保留字典形态的dictmakerarglist的三分支允许f(*args)、f(*args, **kwargs)、f(**kw)等一切调用形态且各分支都接受尾逗号argument: test [comp_for] | test test里comp_for的存在正是生成器表达式的语法入口sum(x for x in it)圆括号可省其上方注释解释了一个精妙的设计关键字参数名在文法层面被写成test而非NAME因为若用NAME会产生歧义f(x1)中x与f(x) 1无法区分真正它必须是 NAME的约束推迟到 ast.c 检查——又一次文法宽松、语义收紧的分工encoding_decl: NAME单独注明 not used in grammar, but may appear in node passed from Parser to Compiler它是# -*- coding: xxx -*-编码声明的载体词法层面产出但不出现在任何产生式里。最难懂的是testlist_safe/old_test/old_lambdef三行紧随suite之后、test之前# Backward compatibility cruft to support: # [ x for x in lambda: True, lambda: False if x() ] # even while also allowing: # lambda x: 5 if x else 2 # (But not a mix of the two) testlist_safe: old_test [(, old_test) [,]] old_test: or_test | old_lambdef old_lambdef: lambda [varargslist] : old_test原文注释自述其存在是向后兼容的遗留设计目的是同时满足两个需求而不允许混搭[ x for x in lambda: True, lambda: False if x() ]——推导式的迭代序列里允许旧式 lambda其函数体是old_test不含if-else 条件式lambda x: 5 if x else 2——独立语句位置的 lambda 函数体可以是完整test含条件式。若把两个 lambda 直接复用[x for x in lambda: True if x else False, ...]会产生for 的迭代序列边界在哪的歧义。于是文法克隆了一套old_前缀的降级 lambda函数体限old_test专门供list_for: for exprlist in testlist_safe [list_iter]的迭代序列使用而comp_for迭代的是or_testcomp_if的条件是old_test——推导式条件位置也因此不能写裸 lambda。这是整份文法中最能体现文法是为了解析器实际行为而逐条打磨的段落理解它基本等于读懂了 BNF 处理歧义的手段。Starlark 侧由于不支持 lambdanot supported: lambda and nested functionstestlist_safe/old_lambdef整套机制在 NextGenIdeabuckGrammar.bnf#L587-L602 中被合并简化list_for/list_if与comp_for/comp_if归并为一组comprehension_iter :: comprehension_for | comprehension_if迭代序列直接用or_expression。类定义与其余零散产生式classdef: class NAME [( [testlist] )] : suiteclassdef允许任意表达式作为基类class A(B(12), C): ...基类本身可以是调用结果基类列表可以是元组class A(B, C)。Starlark 不支持 classuse struct function 代替见 NextGenIdeabuckGrammar.bnf#L566-L567该产生式在 Buck 文法中整体删除。至此Python2Grammar.md 从single_input到yield_expr的全部产生式约 60 个非终结符即已完整覆盖3 个起始符号、10 条函数定义相关、约 30 条语句相关、约 20 条表达式相关外加encoding_decl与yield_expr两个语法外辅助记号。从 Python 2.7 到 StarlarkBuck 如何裁剪这份文法把上文各节中散落的对照集中起来NextGenIdeabuckGrammar.bnf 文件头部L51-L81摘录 Starlark 规范后可以整理出 Buck/Starlark 相对 Python 2.7 的完整删减清单Python 2.7 产生式 / 特性Starlark / Buck 的处置decorator/decorators/decorated删除无证据 Starlark/Buck 支持装饰器print_stmt删除非关键字用内置函数风格del_stmt删除改用dict.pop()等import_stmt含相对导入、*替换为受限的load_callglobal_stmt/exec_stmt删除Starlark 不允许重赋全局变量无 execraise_stmt/yield_stmt/try_stmt/with_stmt删除用fail表达致命错误while_stmt、for/while的else子句删除classdef删除用struct()代替类lambdef、yield_expr、生成器表达式argument中的comp_for入口删除链式比较、is/is not删除跨类型比较未定义与 Python 3 一致反引号原子x、不等号、STRING隐式拼接删除在 Buck 文法中仍保留为comparison_op的历史遗存见 Buck.bnf#L220testlist_safe/old_test/old_lambdef兼容机制随 lambda 一起消失推导子句统一fpdef的括号分组参数、varargslist的顺序约束简化为parameter_list不强制*/**位置同时保留并直接继承的部分可逐条在 Buck.bnf 找到同形产生式条件三元式、or/and/not三级、位运算四级、移位、四则、一元与**、trailer三分支、切片三形态、dict/列表推导、assert两参形式、缩进suite等。换言之Python2Grammar.md 在这套文档里的角色就是裁剪前的全量基准读 Buck 文法时遇到任何一处删改都能回到这份 Python 文法找到被删掉的原产生式。文法如何变成解析器JFlex 与 Grammar-Kit 的两遍生成最后交代这份文法在 Buck 构建中的实际去向。tools/psi-grammar/README.md 说明该模块用 JFlex 生成词法器输入*.flex、用 JetBrains Grammar-Kit 生成解析器输入*.bnf开发时统一用 Buck 构建buck build //tools/psi-grammar:lexers //tools/psi-grammar:parsers对应 tools/psi-grammar/BUCK 中的目标lexersgenruleL4-L17以 Buck.flex 和 Bcfg.flex 为源parsers目标则实现了 README 所述的两遍生成以解决mixin 鸡生蛋问题——Grammar-Kit 解析.bnf里的mixin …BuckNamedElementImpl这类指令时需要已编译的Java 类而编译 mixin 又依赖生成的解析器第一遍BUCK#L63-L70直接跑 Grammar-Kit 生成不认识 mixin 的不完整解析器打包成.src.zip中间步骤BUCK#L79-L95用这份 zip 编译 MIXIN_SRCS 中列出的 18 个手写类如 BuckPsiImplUtil.java并打成_custom_grammarkit可执行 JAR第二遍BUCK#L98-L105用带 mixin 的 Grammar-Kit 重新生成解析器此时.bnf中function_definition、load_argument、identifier等产生式上声明的mixin/implements/methods见 Buck.bnf#L132-L140被正确解析为 PSI 方法getName/setName等最终由java_library目标grammar连同手写源码一起发布给//tools/ideabuck/...使用。NextGenIdeabuckGrammar.bnf 自身不参与构建文件头已声明 This file is not in use by Buck它的用途是给开发者在 IntelliJ 的 Grammar-Kit PsiViewer 实时预览窗里试验这套更贴近 Python 2 文法的原型验证通过后再逐步迁移——这也解释了为什么 Python2Grammar.md 作为参考规范长期保留在docs/目录下。小结tools/psi-grammar/docs/Python2Grammar.md 是 CPython 2.7 解析器文法的完整副本3 个起始符号、约 60 个非终结符覆盖从single_input到yield_expr的全部 Python 2.7 语法其中suite: NEWLINE INDENT stmt DEDENT与 12 级表达式分层是理解缩进如何进入文法与优先级如何由非终结符层级编码的关键它在 Buck 仓库中的定位是基准参照NextGenIdeabuckGrammar.bnf 逐行引用它并在间隙给出 Starlark 的删改与理由Buck.bnf 是实际参与构建的裁剪版文法从文法文件到可运行的 IDE 解析器链路是 JFlex词法 Grammar-Kit 两遍生成语法解决 mixin 编译依赖构建入口见 tools/psi-grammar/BUCK 与 tools/psi-grammar/README.md。赞分享开发工具构建工具【免费下载链接】buckA fast build system that encourages the creation of small, reusable modules over a variety of platforms and languages.项目地址https://gitcode.com/gh_mirrors/bu/buck点击查看免费下载相关推荐Buck psi-grammar 深入解析ideabuck 插件中 BUCK 与 .buckconfig 语法的两遍生成机制Buck psi grammar 深入解析ideabuck 插件中 BUCK 与 .buckconfig 语法的两遍生成机制 psi grammar 是 Bu开发工具构建工具深入解析 .NET runtime 的 IL 语法提取器从 Yacc 文法到 BNF 语法文件深入解析 .NET runtime 的 IL 语法提取器从 Yacc 文法到 BNF 语法文件 导读 在 .NET 开源仓库 runtime https:/语言运行时标准库JIT编译编译器Slang 语法逆向工程参考从 EBNF 文法到解析器实现的完整指南Slang 语法逆向工程参考从 EBNF 文法到解析器实现的完整指南 导读 本文基于 Slang 编译器中逆向工程得到的 EBNF 风格语法参考文档 doc编译器图形学编程语言上一篇如何快速上手InsightFace_Pytorch10分钟搭建人脸识别系统下一篇InfiniteTalk终极指南用AI魔法让图片和视频开口说话创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表