[路飞]_[JS通识]_产生式的定义和写法

824 阅读4分钟

中文的语法,一般的句子是主谓宾结构。有时候没有宾语。

我吃蛋糕。

我是主语。它是由名词或代词构成的。

吃是谓语。一般他是一个动词。

蛋糕是宾语。它同样也是一个名词。

形式化的表达中文的语法:

句子 := 主语 谓语 宾语
主语 := 代词 | 名词 | 短语
代词 := 你 | 我 | 他
...

这个形式,叫产生式(production)。产生产生式的过程,是把一门语言拆分成不同部分的过程,在这个过程中,越来越细化地描述出了这门语言。

在产生式中,主语谓语/名词代词,都是某一语法结构的名称,都称之为Symbol符号)。并把这些语法结构分成非终端结构和终端(Non-Terminal和Terminal的Symbol

非终端结构(非终结符),由多个其他结构经“与”/“或”等逻辑组合得出。

一门语言,就是一个非终端结构。由这个非终端结构的产生式来定义这门语言。所以可以说,定义语言就是定义产生式。

一个中文句子(实例),根据中文的产生式进行拆分得到的,叫做这个句子的语法树

产生式在学界的主流写法——BNF写法

写法如:

         <>::=<>|<>|<>
         <>::=<><><>|<><>
         <>::=<>|<>|<>    
         <>::=""|""|""


<>表示该结构非终端。

""表示该结构为终端。

表示“或”的逻辑。

用来定义中文就是:

         <中文> ::= <句子><中文><句子>
         <句子> ::= <主语><谓语><宾语> | <主语><谓语>
         <主语> ::= <代词> | <名词> | <短语>    
         <代词> ::= "你" | "我" | "他"


BNF写法的升级版EBNF

去掉了表示非终端结构的<>,增加了{}[]

{}表示该结构可一个可多个(就是可重复)。

[]表示该结构可有可没有,可零个可一个(就是可省略)

用来定义中文就是:

         <中文> ::= {句子}
         <句子> ::= 主语 谓语 [宾语]
         <主语> ::= 代词 | 名词 | 短语    
         <代词> ::= "你" | "我" | "他"


用来定义10以内整数的加减乘除就是:

         <10以内整数的加减乘除表达式> ::= {加法算式}
         <加法算式> ::= (加法算式 ("+" | "-") 乘法算式) | 乘法算式  
         <乘法算式> ::= (乘法算式 ("*" | "/") 数字) | 数字   
         <数字> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"


PS:因为乘法比加法的优先级高,所以,乘法算法会形成一个更紧密的语法结构。

JavaScript规范中的产生式写法

截屏2021-11-21 下午8.17.45.png

换行表示“或”的逻辑。

更黑的字体颜色表示终端。(仔细看Block产生式中的{}

利用产生式对形式化语言进行解析

能用产生式描述的语言,叫形式化语言。乔姆斯基作为语言学大牛,定义了几种产生式:

正则文法(3型)
<A>  ::= <A>? 

?表示随便符号都行

正则是正常、正规、regular的意思。js中正则表达式能表达的文法就是正则文法3型文法)。正则文法有一个小规定,就是:产生式的右侧,在递归的情况下,只允许是左递归,就是说,自身递归的部分一定放在左边,非递归的部分一定放在右边,像上文的乘法算式的产生式一样。

上下文无关文法(2型)
<A>  ::= <B>

上下文无关文法2型文法)的语义是:如果说一句句子里出现A,那么,这个A一定由B产生,无论上下文是什么。2型3型是包含的关系,2型包含了3型3型是比2型更严格的一个要求。一般我们说一个产生式是上下文无关文法,那它一般就不是正则文法。

上下文相关文法(1型)
前文巴拉巴拉<A>后文巴拉巴拉  ::= 前文巴拉巴拉<B>后文巴拉巴拉

上下文相关文法1型文法)的语义是:如果说一句句子里出现A,那么,这个A是根据不同的上下文由不同B产生出来的。

无限制文法(0型)
<A> ::= ?

无限制文法0型文法)的语义是:对A的拆分不加限制,随便什么东西都可以生成A。无限制文法没什么实际意义,是语言学家为了完备性做的定义。

词法与语法

解析 JavaScript 等语言的代码字符串,要分为词法语法两个过程,这两个过程离不开乔姆斯基分类出的正则文法和上下文无关文法。

词法语法两个过程要用到词法规范语法规范词法规范语法规范指的是编程语言的词法产生式语法产生式

词法产生式是把编程语言按照正则文法定义的一个语言结构词法过程基于这个结构,将代码字符串的空白/换行/注释和有效内容(Token)分离开来,挑出有效的基本分词(Token)。

挑出了所有token,我们把 token 作为一个输入的流,进入语法过程语法过程基于语法产生式语法产生式是按照2型文法定义的一个语言结构。依据这个结构token 流一步一步聚合成一颗单根的语法树。如果去除一些无用的信息,这颗语法树就变为抽象语法树(AST)。

通过词法产生式语法产生式去“分别”看待一门语言,是最严谨了解一门语言的方式。

PS: 词法(lex) + 语法(syntax) = 文法(grammer)