文法可以分成词法和语法,这来自编译原理的划分,同样是完备的。语义则跟语法具有一一对应关系,这里暂时不区分。 原文地址
-
什么是文法?
- 在编译原理中,文法指的是一套形式化规则,用于精确地定义一个语言的结构。
- 这个“语言”通常指编程语言(如C, Java, Python),但也适用于任何需要精确描述结构的语言(如数学表达式、配置文件格式等)。
- 文法规则规定了:语言中哪些符号序列是合法的(符合语言规范的),哪些是不合法的。
-
为什么需要划分?
- 语言的构造是有层次的。想象一下:
- 最底层:你需要识别出语言中最基本的构件块,比如数字、标识符(变量名)、关键字(
if
,while
)、运算符(+
,=
)、分隔符(;
,{
,}
)等。这些构件块本身是没有复杂内部结构的原子单位。 - 更高层:你需要规定这些基本构件块如何组合起来形成有意义的、结构化的短语,比如表达式(
a + b * 10
)、语句(if (x > 0) { ... }
)、函数定义、程序块等。
- 最底层:你需要识别出语言中最基本的构件块,比如数字、标识符(变量名)、关键字(
- 这种自然的层次结构(原子构件块 → 组合结构)直接导致了文法的划分:词法关注原子构件块,语法关注它们的组合规则。
- 语言的构造是有层次的。想象一下:
-
词法 vs. 语法:
-
词法:
- 关注点: 语言中最小的、有意义的基本符号单元。这些单元被称为 词法单元或记号。
- 规则: 词法规则定义了如何从源代码的字符流中识别出这些记号。
- 例子:
- 如何识别一个
标识符
?(通常以字母或下划线开头,后跟字母、数字或下划线) - 如何识别一个
整数
?(一串数字) - 如何识别一个
字符串字面量
?(以引号开始和结束,中间可以包含转义字符) - 如何识别关键字
if
?(特定的字符序列i
后跟f
) - 如何识别运算符
+
?(单个字符+
)
- 如何识别一个
- 工具: 词法规则通常使用正则表达式来描述。
- 编译器阶段: 词法分析器负责执行词法规则,读取字符流,生成记号流。
-
语法:
- 关注点: 如何将词法分析器产生的记号组合成更大的、有结构的语法单元(如表达式、语句、函数、程序)。
- 规则: 语法规则定义了记号的排列组合方式,规定什么样的记号序列构成了一个合法的程序结构。
- 例子:
- 一个
if语句
的语法:if
(
条件表达式
)
语句
[else
语句
]? - 一个
赋值语句
的语法:标识符
=
表达式
;
- 一个
算术表达式
的语法:表达式
可以是项
或表达式
+
项
或表达式
-
项
;项
可以是因子
或项
*
因子
或项
/
因子
;因子
可以是标识符
|数字
|(
表达式
)
等。
- 一个
- 工具: 语法规则通常使用上下文无关文法来描述(用巴科斯-诺尔范式BNF或其扩展EBNF表示)。
- 编译器阶段: 语法分析器负责执行语法规则,读取记号流,根据语法规则构建语法树(如抽象语法树AST),验证程序结构是否符合语言规范。
-
-
总结理解:
- 词法是关于**“单词”**(记号)本身的构成规则。它回答“什么是这个语言的一个有效单词?”(识别出
int
,123
,"hello"
,+
,;
这些基本单位)。 - 语法是关于**“句子”**(程序结构)的构成规则。它回答“这些单词如何组合成一个有效的句子/程序?”(识别出
int x = 10 + y;
或if (a > b) return a;
这样的结构)。 - 编译过程: 编译器前端首先通过词法分析把源代码字符流变成记号流(识别出单词),然后通过语法分析把记号流组织成语法树(理解句子结构)。没有词法分析识别出的基本单元,语法分析就无法进行;没有语法分析,词法分析识别出的单词就没有结构上的意义。
- 形式化基础: 词法规则对应正则文法(正则表达式),描述的语言是正则语言。语法规则对应上下文无关文法,描述的语言是上下文无关语言。编程语言的词法部分基本都能用正则文法描述,而语法部分则需要更强大的上下文无关文法。
- 词法是关于**“单词”**(记号)本身的构成规则。它回答“什么是这个语言的一个有效单词?”(识别出
简单类比 (自然语言):
- 词法: 定义哪些字符序列是合法的英文单词。规则可能包括:单词由字母组成,不能以数字开头(除特殊情况)等。词法分析器相当于把一段英文文本拆分成一个个独立的单词(token),忽略空格和标点(或者把标点也识别为一种token)。
- 语法: 定义这些单词如何组合成合法的英文句子。规则包括:句子通常有主语+谓语;形容词修饰名词;动词有及物和不及物之分等。语法分析器相当于检查“
The cat sat on the mat.
”是否符合英语语法结构(主谓宾/主谓状),而“Mat the on sat cat the.
”则不符合语法规则。
因此,“文法可以分成词法和语法”这句话在编译原理中的核心含义是:为了高效、清晰地定义和解析编程语言,我们将描述语言结构的规则划分为两个层次:
- 词法规则: 定义语言的基本原子单元。
- 语法规则: 定义这些原子单元如何组合成复杂的、有意义的程序结构。
这种划分是编译器前端设计的理论基础和实践方法。