中文的语法,一般的句子是主谓宾结构。有时候没有宾语。
我吃蛋糕。
我是主语。它是由名词或代词构成的。
吃是谓语。一般他是一个动词。
蛋糕是宾语。它同样也是一个名词。
形式化的表达中文的语法:
句子 := 主语 谓语 宾语
主语 := 代词 | 名词 | 短语
代词 := 你 | 我 | 他
...
这个形式,叫产生式(production)。产生产生式的过程,是把一门语言拆分成不同部分的过程,在这个过程中,越来越细化地描述出了这门语言。
在产生式中,主语谓语/名词代词,都是某一语法结构的名称,都称之为Symbol(符号)。并把这些语法结构分成非终端结构和终端(Non-Terminal和Terminal的Symbol)
非终端结构(非终结符),由多个其他结构经“与”/“或”等逻辑组合得出。
一门语言,就是一个非终端结构。由这个非终端结构的产生式来定义这门语言。所以可以说,定义语言就是定义产生式。
一个中文句子(实例),根据中文的产生式进行拆分得到的,叫做这个句子的语法树
产生式在学界的主流写法——BNF写法
写法如:
<>::=<>|<>|<>
<>::=<><><>|<><>
<>::=<>|<>|<>
<>::=""|""|""
<>表示该结构非终端。
""表示该结构为终端。
|表示“或”的逻辑。
用来定义中文就是:
<中文> ::= <句子>|<中文><句子>
<句子> ::= <主语><谓语><宾语> | <主语><谓语>
<主语> ::= <代词> | <名词> | <短语>
<代词> ::= "你" | "我" | "他"
BNF写法的升级版EBNF
去掉了表示非终端结构的<>,增加了{}和[]。
{}表示该结构可一个可多个(就是可重复)。
[]表示该结构可有可没有,可零个可一个(就是可省略)
用来定义中文就是:
<中文> ::= {句子}
<句子> ::= 主语 谓语 [宾语]
<主语> ::= 代词 | 名词 | 短语
<代词> ::= "你" | "我" | "他"
用来定义10以内整数的加减乘除就是:
<10以内整数的加减乘除表达式> ::= {加法算式}
<加法算式> ::= (加法算式 ("+" | "-") 乘法算式) | 乘法算式
<乘法算式> ::= (乘法算式 ("*" | "/") 数字) | 数字
<数字> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
PS:因为乘法比加法的优先级高,所以,乘法算法会形成一个更紧密的语法结构。
JavaScript规范中的产生式写法
换行表示“或”的逻辑。
更黑的字体颜色表示终端。(仔细看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)