起步
物理行: 由 回车字符 结尾的字符序列组成一个物理行.
逻辑行: 由一个或者多个物理行组成,可以明确地使用反斜杠(\)来连接多行物理行.
s = "hello \
wolrd"
s = """
hello
world
"""
l = [
1,
2,
]
d = {
"a": 1,
"b": 2,
}
Grammar 文件
[Grammar]
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
Lable
[grammar.h]
typedef struct {
int lb_type;
char *lb_str;
} label;
arc
typedef struct {
short a_lbl; /* Label of this arc */
short a_arrow; /* State where this arc goes to */
} arc;
state
/* A state in a DFA */
typedef struct {
int s_narcs;
arc *s_arc; // 出发边的集合
/* Optional accelerators */
int s_lower; /* Lowest label index */
int s_upper; /* Highest label index */
int *s_accel; /* Accelerator */
int s_accept; /* Nonzero for accepting state */
} state;
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;
} dfa;
grammar
typedef struct {
int g_ndfas;
dfa *g_dfa; /* Array of DFAs */
labellist g_ll;
int g_start; /* Start symbol of the grammar */
int g_accel; /* Set if accelerators present */
} grammar;
语法结构的搭建
static arc arcs_0_0[3] = {
{2, 1},
{3, 1},
{4, 2},
};
static arc arcs_0_1[1] = {
{0, 1},
};
static arc arcs_0_2[1] = {
{2, 1},
};
static dfa dfas[86] = {
{256, "single_input", 0, 3, states_0,
"\004\050\340\000\002\000\000\000\012\076\011\007\262\004\020\002\000\300\220\050\037\102"},
{257, "file_input", 0, 2, states_1,
"\204\050\340\000\002\000\000\000\012\076\011\007\262\004\020\002\000\300\220\050\037\102"},
...
};
static label labels[176] = {
{0, "EMPTY"},
{256, 0},
{4, 0},
{270, 0},
...
};
grammar _PyParser_Grammar = {
86,
dfas,
{176, labels},
256
};
Accelerators
[acceler.c]
void PyGrammar_AddAccelerators(grammar *g)
{
dfa *d;
int i;
d = g->g_dfa;
for (i = g->g_ndfas; --i >= 0; d++)
fixdfa(g, d);
g->g_accel = 1;
}
[acceler.c]
static void fixdfa(grammar *g, dfa *d)
{
state *s;
int j;
s = d->d_state;
for (j = 0; j < d->d_nstates; j++, s++)
fixstate(g, s);
}
申请一个与 labels 个数相等的int数组空间, 让 accel 变量指向这个内存空间, 每个元素都初始为 -1 .
处理 state 的每条边 arc . 这个处理又分为3个情况:
如果该边的 label 是终结符, 则设置 accel[ibit] = a->a_arrow , 即目标状态, 这种情况下, 不会进入到另一个 DFA.
如果这条边的 label 是非终结符, 则找到对应的 DFA, 对 firstset 中每个 label 的 ibit 设置 accel[ibit] = 目标DFA+该边的目标状态
如果该边的 label 是 "EMPTY" , 则设置 s_accept=1 表明该状态为结束状态.
最后, 计算出 accel 数组中的最小边界和最大边界, 放到 s_lower 和 s_upper 中. 小于 s_lower 和大于 s_upper 的数组位置都是没有初始化过的, 因此此时的这部分没有意义了, 用 copy 把处于 [s_lower : s_upper+1] 之间内容取出. 计算一个 state 完毕.
PyParser
[node.h]
typedef struct _node {
short n_type;
char *n_str;
int n_lineno;
int n_col_offset;
int n_nchildren;
struct _node *n_child;
} node;
成员
说明
n_type
结点类型,终结符定义在token.h中,而非终结符定义在graminit.h中
n_str
结点所对应的字符串的内容
n_lineno
对应的行号
n_col_offset
列号
n_nchildren
子结点的个数
n_child
子结点数组,动态分配内存
[parser.h]
#define MAXSTACK 1500
typedef struct {
int s_state; // 当前dfa中的状态
dfa *s_dfa; // 当前的dfa指针
struct _node *s_parent; // 当前的父节点, PyParser会把新的结点作为Child加到栈顶状态的s_parent结点中去
} stackentry;
typedef struct {
stackentry *s_top; /* Top entry */
stackentry s_base[MAXSTACK];/* Array of stack entries */
/* NB The stack grows down */
} stack;
typedef struct {
stack p_stack; // PyParser状态栈
grammar *p_grammar; // 语法图指针
node *p_tree; // CST根节点
unsigned long p_flags;// PyParser的flags
} parser_state;
[parser.h]
parser_state *PyParser_New(grammar *g, int start);
void PyParser_Delete(parser_state *ps);
int PyParser_AddToken(parser_state *ps, int type, char *str, int lineno, int col_offset,
int *expected_ret);
void PyGrammar_AddAccelerators(grammar *g);
[parsetok.c parsetok]
// 省略了很多代码
ps = PyParser_New(g, start);
for (;;) {
char *a, *b;
int type;
size_t len;
char *str;
int col_offset;
type = PyTokenizer_Get(tok, &a, &b);
PyParser_AddToken(ps, (int)type, str,
tok->lineno, col_offset,
&(err_ret->expected))
}
PyParser API
[parsetok.h]
PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int,
perrdetail *);
PyAPI_FUNC(node *) PyParser_ParseFile (FILE *, const char *, grammar *, int,
const char *, const char *,
perrdetail *);
PyAPI_FUNC(node *) PyParser_ParseStringFlags(const char *, grammar *, int,
perrdetail *, int);
...
PyParser_AddToken