Grammar文件
前面提到了在Python的源代码目录下面有一个Grammar目录,里面只有一个文件Grammar,以BNF的语法定义了Python的全部语法。拿if语句举例来说:
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] |
上面的语句可以这样理解,if语句是if关键字+逻辑表达式+ ‘:’+语句块(suite)后面跟上0至多个elif语句并以else语句结束。在最左边的if_stmt表示这一句话定义了if_stmt(非终结符),’:’右边则是if_stmt的具体对应的内容。
1. ‘’引号中的内容是实际的字符串,’if’就代表if这两个字符
2. 一般的标示符代表着非终结符,也就是某个等式的左边,if_stmt, test, suite都是非终结符,可以被扩展为等式右边的序列。
3. ()括号是原子操作符,被括号括起来的被作为单个表达式看待
4. *代表0或多个,比如在if_stmt中的(‘elif’ test ‘:’ suite)*代表一个if语句中可以有0或者多个elif子句
5. +代表1或者多个
但是,这个文件并不只是用来作为参考资料的。实际上,Python运行的时候也需要间接利用到Grammar文件的内容来进行语法分析。
PGEN
在Makefile.pre.in和Parser/grammar.mak中均有类似如下的代码:
########################################################################## # Grammar GRAMMAR_H= $(srcdir)/Include/graminit.h GRAMMAR_C= $(srcdir)/Python/graminit.c GRAMMAR_INPUT= $(srcdir)/Grammar/Grammar ########################################################################## # Parser PGEN= Parser/pgen$(EXE) Parser/acceler.o / Parser/grammar1.o / Parser/listnode.o / Parser/node.o / Parser/parser.o / Parser/parsetok.o / Parser/bitset.o / Parser/metagrammar.o / Parser/firstsets.o / Parser/grammar.o / Parser/pgen.o PARSER_OBJS= $(POBJS) Parser/myreadline.o Parser/tokenizer.o
PGOBJS= / Objects/obmalloc.o / Python/mysnprintf.o / Parser/tokenizer_pgen.o / Parser/printgrammar.o / Parser/pgenmain.o
PGENOBJS= $(PGENMAIN) $(POBJS) $(PGOBJS)
############################################################################ # Special rules for object files $(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT) -$(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)
$(PGEN): $(PGENOBJS) $(CC) $(OPT) $(LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
|
这段代码负责生成pgen,然后调用pgen以Grammar作为输入,生成graminit.h/graminit.c。PGEN是Python自带的语法分析数据生成的工具,负责分析Grammar然后生成对应的graminit.c/graminit.h。然后,Python在运行过程中会依赖graminit.c/graminit.h中的数据结构来进行语法分析。PGEN的具体实现不在本文讨论范围中,从略。
Grammar.h
Graminit.c中定义了包括Python<