python 编译过程 从py文件到bytecode
来源:互联网 发布:销售返利软件 编辑:程序博客网 时间:2024/06/08 15:00
在os 角度,文件最终由file_str 来表示一个文件,我们从
mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str);
作为今天追踪代码的起点。
raw_code 这个结构体我们已经看到好多次了,里面放了有bytecode 这么一个成员。
typedef struct _mp_raw_code_t { mp_raw_code_kind_t kind : 3; mp_uint_t scope_flags : 7; mp_uint_t n_pos_args : 11; union { struct { const byte *bytecode; const mp_uint_t *const_table; #if MICROPY_PERSISTENT_CODE_SAVE mp_uint_t bc_len; uint16_t n_obj; uint16_t n_raw_code; #endif } u_byte; struct { void *fun_data; const mp_uint_t *const_table; mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc } u_native; } data;} mp_raw_code_t;
mp_raw_code_load_file从字面意思就可以看出,是要将一个(py)文件load到内存,官方说法就是将这个文件的内容跟我们现在的进程建立某种
联系,此时文件便成了这个进程的某种资源(财产)。
我们来看看此函数的实现
mp_raw_code_t *mp_raw_code_load_file(const char *filename) { mp_lexer_file_buf_t fb; fb.fd = open(filename, O_RDONLY, 0644); int n = read(fb.fd, fb.buf, sizeof(fb.buf)); fb.len = n; fb.pos = 0; mp_reader_t reader; reader.data = &fb; reader.read_byte = file_buf_next_byte; mp_raw_code_t *rc = mp_raw_code_load(&reader); close(fb.fd); return rc;}
第一个函数调用必然是打开文件, 打开文件,我就会得到一个文件描述符, 此函数位于syscalls.c 文件中
有兴趣的读者可以参考关于Linux 文件相关章节
如何由py文件生成lex
mp_lexer_t *lex = mp_lexer_new_from_file(file);
lex 定义在lexer.h里面
// this data structure is exposed for efficiency// public members are: source_name, tok_line, tok_column, tok_kind, vstrtypedef struct _mp_lexer_t { qstr source_name; // name of source void *stream_data; // data for stream mp_lexer_stream_next_byte_t stream_next_byte; // stream callback to get next byte mp_lexer_stream_close_t stream_close; // stream callback to free unichar chr0, chr1, chr2; // current cached characters from source mp_uint_t line; // current source line mp_uint_t column; // current source column mp_int_t emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit mp_int_t nested_bracket_level; // >0 when there are nested brackets over multiple lines mp_uint_t alloc_indent_level; mp_uint_t num_indent_level; uint16_t *indent_level; mp_uint_t tok_line; // token source line mp_uint_t tok_column; // token source column mp_token_kind_t tok_kind; // token kind vstr_t vstr; // token data} mp_lexer_t;
这个结构体大致分为了两部分,第一部分描述源文件相关信息,第二部分描述生成的token.
注释也说了,公开的成员只有source_name, tok_line, tok_column, tok_kind, vstr.
个人认为vstr是最重要的一个成员,最后拆出来的一个个token就是放在这个位置的。
我们继续往下读
mp_lexer_t *mp_lexer_new_from_file(const char *filename) { int fd = open(filename, O_RDONLY, 0644); if (fd < 0) { return NULL; } return mp_lexer_new_from_fd(qstr_from_str(filename), fd, true);}第一部分,只是得到一个fd. fd仅仅是一个int 型变量,主要就是在MinFd 和OPEN_MAX之间找到一个空闲的
/* Find and reserve a free File Descriptor. Returns the first free File Descriptor greater than or equal to the, already validated, fd specified by Minfd. @return Returns -1 if there are no free FDs. Otherwise returns the found fd.*/intFindFreeFD( int MinFd ){ struct __filedes *Mfd; int i; int fd = -1; Mfd = gMD->fdarray; // Get an available fd for(i=MinFd; i < OPEN_MAX; ++i) { if(Mfd[i].f_iflags == 0) { Mfd[i].f_iflags = FIF_LARVAL; // Temporarily mark this fd as reserved fd = i; break; } } return fd;}
void vstr_reset(vstr_t *vstr) { vstr->len = 0; vstr->had_error = false;}
STATIC bool is_end(mp_lexer_t *lex) { return lex->chr0 == MP_LEXER_EOF;}
vstr 往后移动
char *vstr_add_len(vstr_t *vstr, size_t len) { if (vstr->had_error || !vstr_ensure_extra(vstr, len)) { return NULL; } char *buf = vstr->buf + vstr->len; vstr->len += len; return buf;}
代码分析过程就是从stack 里面拿出一个个规则rule去匹配。
所以每次分析的第一步必然是 pop_rule();
那么第一个pop出来是谁push 进去的呢?
在parse 之前,就会根据输入类型来push 一个rule 进来。
switch (input_kind) { case MP_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break; case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break; default: top_level_rule = RULE_file_input; } push_rule(&parser, lex->tok_line, rules[top_level_rule], 0); // parse!
push 的意思是将某些内容保存起来,实例化一个 rule_stack_t . 然后给每个成员赋值。
STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t arg_i) { if (parser->parse_error) { return; } if (parser->rule_stack_top >= parser->rule_stack_alloc) { rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC, true); if (rs == NULL) { parser->parse_error = PARSE_ERROR_MEMORY; return; } parser->rule_stack = rs; parser->rule_stack_alloc += MICROPY_ALLOC_PARSE_RULE_INC; } rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++]; rs->src_line = src_line; rs->rule_id = rule->rule_id; rs->arg_i = arg_i;}
我们从源文件或者str 中读出来供lexer吃,可是什么时候,是个头呢? 换句话说,读到啥时候,就不读了? 这个问题,由while 循环来解决。
// get tail chars while (!is_end(lex) && is_tail_of_identifier(lex)) { vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); next_char(lex); }
当我们读到一行结尾,并且不是顶层缩进,那么,我们认为读到了程序末尾, 置tok_kind 为MP_TOKEN_END;
(is_end(lex)) { if (indent_top(lex) > 0) { lex->tok_kind = MP_TOKEN_NEWLINE; lex->emit_dent = 0; while (indent_top(lex) > 0) { indent_pop(lex); lex->emit_dent -= 1; } } else { lex->tok_kind = MP_TOKEN_END; }
0 0
- python 编译过程 从py文件到bytecode
- python语言的本质-- 从bytecode 到虚拟机
- 从Java文件的编译到最终执行的过程
- 从Java文件的编译到最终执行的过程
- 整理综合之一 ----从Bytecode到BasicBlock
- Python从入门到PY交易,基础语法,散记(一)
- Python从入门到PY交易,基础语法,散记(二)
- python 把py文件编译为pyc文件 商业用途
- jython 2.5后, 编译.py文件到.class的方法
- python ByteCode
- 【Python学习】源文件py编译为pyc文件
- python对于.py文件的编译和解释
- 工作流文件从编译到运行编译
- python __init__.py文件
- Python 调用py文件
- 把py编译到pyc
- 从luajit bytecode dump文件提取字符串资源
- luajit笔记---编译bytecode(字节码文件)
- java8之接口的默认静态方法
- 【操作系统】死锁-思维导图
- 三种动画效果(Frame, View, Property)实现
- 《Windows环境下32位汇编语言程序设计(第2版)》-chapter3补
- listen()函数中backlog参数分析
- python 编译过程 从py文件到bytecode
- 【操作系统】处理机调度-思维导图
- HDU 1358 Period (kmp求循环节)
- LightOJ 1010 Knights in Chessboard <贪心思维>
- 【Codeforces 597A】A. Divisibility
- NOIP 模拟题 C17 [容斥原理]
- HDU 5747 Aaronson(汉明距离)
- 【操作系统】线程的实现-思维导图
- {学习笔记}[内省]