×

cf文法

cf文法,上下文无关文法(CF文法)入门攻略,从概念到实践

okx okx 发表于2026-04-24 09:45:23 浏览3 评论0

抢沙发发表评论

本文目录导读:

  1. 什么是CF文法?
  2. CF文法的四元组定义
  3. 如何用CF文法生成句子?
  4. 语法树:直观理解结构
  5. CF文法的实际用途
  6. 如何构造一个CF文法?
  7. 常见陷阱与应对策略
  8. 实战:用CF文法设计一个迷你计算器
  9. 总结与进阶

什么是CF文法?

cf文法,上下文无关文法(CF文法)入门攻略,从概念到实践

CF文法(Context-Free Grammar,上下文无关文法)是形式语言理论中的核心概念,也是编译原理、自然语言处理、程序设计语言设计的基础工具,它是一套生成字符串的规则系统,能够描述大多数编程语言的语法结构。

想象一下,你有一座“语言工厂”,里面有两种零件:

  • 终结符:不可再分解的基本符号(如数字、运算符、关键字)
  • 非终结符:可以进一步展开的抽象概念(如“表达式”、“语句”)

工厂的规则叫产生式,形如:
非终结符 → 一串终结符和非终结符

描述一个简单算术表达式:

Expr → Expr '+' Term   |   Term
Term → Term '*' Factor  |   Factor
Factor → '(' Expr ')'   |   'id'   |   'num'

这条规则说:“一个表达式可以是另一个表达式加一个项,或者直接就是一个项”,这就是典型的CF文法。


CF文法的四元组定义

一个完整的CF文法由四部分组成:

G = (V, T, P, S)
  • V:非终结符集合(变量,如Expr、Term)
  • T:终结符集合(字母表上的符号,如'+', '*', 'id')
  • P:产生式集合(规则)
  • S:开始符号(属于V,文法生成的起点)

例如上面算术表达式的文法中:
V = {Expr, Term, Factor}
T = { '+', '*', '(', ')', 'id', 'num' }
P = 上述三条产生式
S = Expr


如何用CF文法生成句子?

“推导”是核心操作,从开始符号出发,反复将非终结符替换为产生式右部,直到所有符号都变成终结符。

例子:生成句子 id + id * id

Expr
→ Expr '+' Term           (使用 Expr → Expr '+' Term)
→ Term '+' Term           (替换第一个Expr为Term)
→ Factor '+' Term         (替换Term为Factor)
→ id '+' Term             (Factor → 'id')
→ id '+' Term '*' Factor  (Term → Term '*' Factor)
→ id '+' Factor '*' Factor(Term → Factor)
→ id '+' id '*' Factor    (Factor → 'id')
→ id '+' id '*' id        (Factor → 'id')

每一步替换都只依赖被替换符号本身,不依赖上下文——这就是“上下文无关”的含义。


语法树:直观理解结构

推导过程可以画成一棵倒立的树——语法分析树(Parse Tree),根节点是开始符号,叶子节点是终结符,内部节点是非终结符。

对于上面的推导,语法树如下:

        Expr
       /  |  \
    Expr  '+'  Term
      |        / | \
    Term    Term '*' Factor
      |       |        |
   Factor   Factor    'id'
      |        |
    'id'      'id'

语法树清晰地展示了运算符优先级:乘法先结合,加法后结合。


CF文法的实际用途

编译原理中的语法分析

几乎所有编程语言的语法都用CF文法定义(如C、Java、Python),编译器前端通过递归下降解析LR解析,将源代码读入并建立语法树。

自然语言处理

句子的语法结构可以用CF文法表示。
S → NP VP(句子由名词短语和动词短语组成)
NP → Det N(名词短语由限定词和名词组成)

数据格式描述

JSON、XML、HTML的语法都可以用CF文法描述,例如JSON的简化文法:

Value → Object | Array | String | Number | true | false | null
Object → '{' Pair (',' Pair)* '}' | '{' '}'
Pair → String ':' Value

如何构造一个CF文法?

步骤1:明确要描述的语言是什么(集合)。
所有由a和b组成的、且a的数量等于b的数量的字符串。

步骤2:设计递归的生成规则。
上述语言满足:

  • 空串属于语言
  • 如果S属于语言,则 aSb 也属于(在两边各加一个a和b)
  • 如果S1、S2属于语言,则 S1S2 也属于

由此得到文法:

S → ε | a S b | S S

步骤3:检查文法是否产生多余或错误的字符串。
例如上述文法可能产生重复问题,通常我们会用更精确的写法:

S → a S b S | ε

这个文法能保证所有合法的字符串都被生成。


常见陷阱与应对策略

左递归

形如 A → A α 的产生式会导致递归下降解析器陷入无限循环。
解决方法:消除左递归(通过引入新非终结符改写)

Expr → Expr '+' Term | Term

改写为:

Expr → Term Expr'
Expr' → '+' Term Expr' | ε

二义性

同一个句子对应多棵不同的语法树,例如经典“悬挂else”问题:

if C1 then if C2 then S1 else S2

可能有两种解释。解决方法:通过优先级规则或修改文法(如强制else匹配最近的if)。

左公因子

两个产生式以相同前缀开头,导致预测时无法选择。解决方法:提取左公因子。


实战:用CF文法设计一个迷你计算器

目标:支持加、乘、括号,数字为整数(id)。

文法设计

Expr → Expr '+' Term | Term
Term → Term '*' Factor | Factor
Factor → '(' Expr ')' | NUMBER

(注意:这里NUMBER是终结符,实际词法分析器会识别)

测试:输入 (2 + 3) * 5
推导如下(简化):

Expr → Term → Term '*' Factor → Factor '*' Factor → '(' Expr ')' '*' Factor
→ '(' Expr '+' Term ')' '*' Factor → '(' Term '+' Term ')' '*' Factor
→ '(' Factor '+' Factor ')' '*' Factor → '(' NUMBER '+' NUMBER ')' '*' NUMBER

解析结果:语法树保证了乘法优先级高于加法(因为乘法在更低层)。


总结与进阶

CF文法是理解计算机语言的一把金钥匙,掌握它之后,你可以:

  • 编写简单的解释器或编译器
  • 理解编程语言中的语法错误提示
  • 设计DSL(领域特定语言)

下一步推荐学习

  • 自顶向下解析(LL(1))与自底向上解析(LR(0)、SLR、LALR)
  • 语法制导翻译(属性文法)
  • Chomsky文法分类体系(0~3型,CF属于2型)

CF文法的核心魅力在于:用有限的规则生成无限的语言,动手写几条文法,用在线工具(如Grammophone、ANTLR)测试一下,你会很快上手!