Python 元语法 MetaGrammar - DFA数据结构及生成

Python 元语法 MetaGrammar

Python的语法文件Grammar定义了Python的文法规则,该语法文件也有其文法,Python的程序pgen用来将语法文件生成graminit.h/graminit.c,用来编译Python的编译器,具体来说,元语法在pgen程序里面,用来解析Python的语法文件Grammar/Grammar,生成Python语法的DFA状态图,以及用来将实际的Python代码.py文件词法分析后的Token序列转化成解析树ParseTree,最后生成抽象语法树AST

本文主要分析pgen程序生成元语法的DFA状态图的过程,以及其数据结构和生成流程

1. pgen.c 的尾部说明:

/*
Description
-----------

Input is a grammar in extended BNF (using * for repetition, + for
at-least-once repetition, [] for optional parts, | for alternatives and
() for grouping).  This has already been parsed and turned into a parse
tree.

Each rule is considered as a regular expression in its own right.
It is turned into a Non-deterministic Finite Automaton (NFA), which
is then turned into a Deterministic Finite Automaton (DFA), which is then
optimized to reduce the number of states.  See [Aho&Ullman 77] chapter 3,
or similar compiler books (this technique is more often used for lexical
analyzers).

The DFA's are used by the parser as parsing tables in a special way
that's probably unique.  Before they are usable, the FIRST sets of all
non-terminals are computed.

Reference
---------

[Aho&Ullman 77]
    Aho&Ullman, Principles of Compiler Design, Addison-Wesley 1977
    (first edition)
*/

2. 概念复习

2.1 非终结符的FIRST集

First(A) 表示非终结符A的产生式中首个终结符的集合

2.2 非终结符的FOLLOW集

Follow(A) 表示非终结符A后的首个终结符的集合,不包含空串

3. 元语法文件

MSTART: (NEWLINE | RULE)* ENDMARKER
RULE: NAME ':' RHS NEWLINE
RHS: ALT ('|' ALT)*
ALT: ITEM+
ITEM: '[' RHS ']' | ATOM ['*' | '+']
ATOM: NAME | STRING | '(' RHS ')'

Python’s compiler - from grammar to dfa

元语法文件说明:
起始标记:MSTART
MSTART:由0-n个(NEWLINE 或者 RULE)加上 结束标记
RULE:由变量名 加上 “:” 加上 RHS 加上换行(NEWLINE)

4. 元语法定义

// 获取元语法的函数方法
grammar *
meta_grammar(void)
{
    // 返回元语法定义结构体首地址
    return &_PyParser_Grammar;
}

// 元语法定义结构体
static grammar _PyParser_Grammar = {
    6,                           // 6个DFA
    dfas,                        // DFA数组首地址
    {19, labels},                // 有19个标记
    256                          // 起始的DFA的TYPE为256
};

// 元语法包含6中DFA
static dfa dfas[6] = {
    // lable type, Token类型
    // label name, Token名称
    // initial state, 初始状态
    // state count, 状态个数
    // states, 状态数组
    // first set,Token的FIRST集 
    {256, "MSTART", 0, 2, states_0, "\070\000\000"},
    {257, "RULE",   0, 5, states_1, "\040\000\000"},
    {258, "RHS",    0, 2, states_2, "\040\010\003"},
    {259, "ALT",    0, 2, states_3, "\040\010\003"},
    {260, "ITEM",   0, 5, states_4, "\040\010\003"},
    {261, "ATOM",   0, 4, states_5, "\040\000\003"},
};

// 元语法中DFA状态转移用到的Token
// >= 256 为非终结符 < 256 为终结符
static label labels[19] = {
    {0, "EMPTY"},  // ENDMARKER 表示结束标记
    {256, 0},      // MSTART
    {257, 0},      // RULE 
    {4, 0},        // NEWLINE(换行符)
    {0, 0},        // ENDMARKER 
    {1, 0},        // NAME()
    {11, 0},       // COLON(冒号)
    {258, 0},      // RHS
    {259, 0},      // ALT
    {18, 0},       // VBAR(竖线)
    {260, 0},      // ITEM
    {9, 0},        // LSQB(左方括号) 
    {10, 0},       // RSQB(右方括号)
    {261, 0},      // ATOM
    {16, 0},       // STAR(星号)
    {14, 0},       // PLUS(加号)
    {3, 0},        // STRING(字符串)
    {7, 0},        // LPAR(左括号)
    {8, 0},        // RPAR(右括号)
};

5. 元语法文件的DFA数据结构

DFA的结构体定义:

typedef struct {
    int		 d_type;	/* Non-terminal this represents */ // 代表非终结符
    char	*d_name;	/* For printing */                 // 名称,打印使用
    int		 d_initial;	/* Initial state */                // 初始状态
    int		 d_nstates;                                    // 可迁移状态的数量                    
    state	*d_state;	/* Array of states */              // 状态集
    bitset	 d_first;                                      // 该非终结符的FIRST集(为一个字节数组,八进制表示?这里还是有点不明白)
} dfa;

来看一下DFA状态state的定义:

typedef struct {
    int		 s_narcs;                                     // 状态转移(边)的个数 
    arc		*s_arc;		/* Array of arcs */               // 状态转移数组首地址
	
    /* Optional accelerators */
    int		 s_lower;	/* Lowest label index */          // 最小的label的index 
    int		 s_upper;	/* Highest label index */         // 最大的label的index
    int		*s_accel;	/* Accelerator */                 // 加速器 ?
    int		 s_accept;	/* Nonzero for accepting state */ // 非零表示该状态被接收
} state;

再看一下DFA边arc的定义:

// 状态转移(边)的定义
typedef struct {
    short	a_lbl;		/* Label of this arc */               // 当前状态上的输入label[index]
    short	a_arrow;	/* State where this arc goes to */    // 可以转移到的当前状态state[index]
} arc;

再看一下DFA边上的label的定义:
label就是一个状态转移到另一个状态时的input输入,也就是输入一个非终结符可以是状态发生转移

typedef struct {
    int		 lb_type;  // label的类型
    char	*lb_str;   // label的input输入值
} label;

6. 元语法的DFA的分析

元语法定义中有6个正规式,对应6个DFA

来看第一个正规式:

MSTART: (NEWLINE | RULE)* ENDMARKER

第一个DFA:

{256, "MSTART", 0, 2, states_0, "\070\000\000"}

解释说明:
type: 256
name: “MSTART”
initial: 0
nstates: 2
state *: states_0 ----- DFA的状态集
bitset: “\070\000\000”

这个DFA的状态集:states_0,包含2个状态节点,第一个节点上有3条边,第二个节点上有1条边

// DFA的状态节点集和 
static state states_0[2] = {   // 有2个状态节点
    {3, arcs_0_0},             // 有3种状态转移,转移集合为 arcs_0_0
    {1, arcs_0_1},             // 有1装状态转移,转移集合为 arcs_0_1
};
// 第一个状态节点
static arc arcs_0_0[3] = {     // 有3种状态转移(边)
    {2, 0},                    // 输入为 label[2] 可以转移到状态 states_0[0]
    {3, 0},                    // 输入为 label[3] 可以转移到状态 states_0[0]
    {4, 1},                    // 输入为 label[4] 可以转移到状态 states_0[1]
};
// 第二个状态节点
static arc arcs_0_1[1] = {     // 有2种状态转移(边) 
    {0, 1},                    // 输入为 label[0] 可以转移到状态 states_0[1]
};

其中label的定义如下:

label[0] = ENDMARKER
label[1] = MSTART
label[2] = RULE
lable[3] = NEWLINE
label[4] = ENDMARKER

在这里插入图片描述

第二个正规式:

RULE: NAME ':' RHS NEWLINE

其DFA定义:

{257, "RULE",   0, 5, states_1, "\040\000\000"},

这个DFA有5个状态节点:

static state states_1[5] = {
    {1, arcs_1_0},
    {1, arcs_1_1},
    {1, arcs_1_2},
    {1, arcs_1_3},
    {1, arcs_1_4},
};

static arc arcs_1_0[1] = {
    {5, 1},  // label[5] -> states_1[1]
};
static arc arcs_1_1[1] = {
    {6, 2},  // label[6] -> states_1[2]
};
static arc arcs_1_2[1] = {
    {7, 3},  // label[7] -> states_1[3]
};
static arc arcs_1_3[1] = {
    {3, 4},  // label[3] -> states_1[4]
};
static arc arcs_1_4[1] = {
    {0, 4},  // label[0] -> states_1[4]
};

其中label的定义如下:

label[0] = ENDMARKER
label[3] = NEWLINE
label[5] = NAME
lable[6] = COLON
label[7] = RHS

元语法加载出来之后,我们试着用元语法来生成一个语法文件grammar.txt的DFA数据结构
grammar.txt 这个文件的内容:

arglist: NUMBER (',' NUMBER)*  [',']

这个语法文件的意思是一条规则:arglist,由 NUMBER 加上 0个或多个(逗号 NUMBER) 加上 逗号 组成

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值