feat(vast_c): C 版解析器阶段 0——赋值/名字/数字子集,直接构造 vast.nodes 树

- MSYS2 MinGW gcc 编译 CPython 3.12 C 扩展(_parser.pyd,-lpython312 必须置于源文件后)
- Tokenizer + 表达式/赋值/模块解析,节点通过 PyObject_Vectorcall 直接实例化 lib.vast.Nodes 类
- 输出与 vast.parse 结构完全一致(含位置属性),eval 模式复用 vast.parse 语义
- 可行性验证:200 语句文件 × 200 次基准 9.0x 加速(6.17ms -> 0.685ms/次),C 侧开销主要在节点构造,后续可继续优化
This commit is contained in:
TermiNexus committed 2026-08-18 05:45:11 +08:00
1 parent e3886a244d
commit 0d15e8cb7a
2 files changed
+504

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
"""vast_c - C 版 Viper/Python 语法解析器(vast 加速层)
C 扩展 _parser.pyd 直接构造 lib.vast.Nodes 的节点类实例,
输出与 vast.parse 结构完全一致。当前为阶段 0(赋值/名字/数字子集),
后续阶段将覆盖完整 Python 3.12 语法 + Viper 扩展(extern/export/软关键字)。
"""
from lib.vast_c._parser import parse
__all__: list[str] = ['parse']
+495
View File
@@ -0,0 +1,495 @@
/* vast_c - C 版 Viper/Python 语法解析器(vast 加速层)
*
* 阶段 0:最小可行性验证——Tokenizer + 表达式/赋值/模块解析,
* 直接构造 lib.vast.Nodes 的节点类实例,输出与 vast.parse 结构完全一致。
*
* 编译(MSYS2 MinGW gcc,Python 3.12,注意 -l 必须在源文件之后):
* gcc -shared -O2 -std=c11 -I D:\Python312\include lib\vast_c\vast_c.c \
* -L D:\Python312\libs -lpython312 -o lib\vast_c\_parser.pyd
*
* 使用:
* from lib.vast_c import parse # 由 lib/vast_c/__init__.py 导出
* tree = parse("x = 1") # 与 vast.parse 同结构
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
/* ================= 记号(Token) ================= */
typedef enum {
TK_EOF = 0,
TK_NAME,
TK_NUMBER,
TK_EQUAL,
TK_LPAREN,
TK_RPAREN,
TK_NEWLINE,
} TokenKind;
typedef struct {
TokenKind Kind;
const char *Start;
Py_ssize_t Len;
int Line;
int Col;
} Token;
/* ================= 解析器(Parser) ================= */
typedef struct {
const char *Src;
Py_ssize_t Len;
Py_ssize_t Pos;
int Line;
int Col;
Token Cur;
int Error;
} Parser;
/* vast.nodes 模块与节点类缓存(进程级惰性初始化) */
static PyObject *s_Nodes = NULL;
static PyObject *s_Classes = NULL; /* dict: 类名 -> 类对象 */
static PyObject *NodesModule(void) {
if (s_Nodes == NULL) {
s_Nodes = PyImport_ImportModule("lib.vast.Nodes");
}
return s_Nodes;
}
/* 获取节点类对象(borrowed 引用,内部缓存避免重复属性查找) */
static PyObject *ClassGet(Parser *P, const char *Name) {
PyObject *Mod = NodesModule();
if (Mod == NULL) {
return NULL;
}
if (s_Classes == NULL) {
s_Classes = PyDict_New();
if (s_Classes == NULL) {
return NULL;
}
}
PyObject *Key = PyUnicode_FromString(Name);
if (Key == NULL) {
return NULL;
}
PyObject *Cls = PyDict_GetItemWithError(s_Classes, Key); /* borrowed */
if (Cls == NULL && !PyErr_Occurred()) {
Cls = PyObject_GetAttrString(Mod, Name);
if (Cls == NULL) {
Py_DECREF(Key);
return NULL;
}
if (PyDict_SetItem(s_Classes, Key, Cls) < 0) {
Py_DECREF(Cls);
Py_DECREF(Key);
return NULL;
}
}
Py_DECREF(Key);
return Cls; /* borrowed */
}
/* 构造节点:按位置参数数组调用类(vast.nodes 的 __init__(*args, **kwargs)) */
static PyObject *NodeMake(Parser *P, const char *Name, PyObject **Args, Py_ssize_t NArgs) {
PyObject *Cls = ClassGet(P, Name);
if (Cls == NULL) {
return NULL;
}
return PyObject_Vectorcall(Cls, Args, NArgs, NULL);
}
/* 设置位置属性(vast.parse 默认携带 lineno/col_offset/end_lineno/end_col_offset) */
static void NodePos(Parser *P, PyObject *Node, int Line, int Col) {
PyObject *LineObj = PyLong_FromLong(Line);
PyObject *ColObj = PyLong_FromLong(Col);
PyObject *EndLineObj = PyLong_FromLong(P->Line);
PyObject *EndColObj = PyLong_FromLong(P->Col);
if (LineObj && ColObj && EndLineObj && EndColObj) {
PyObject_SetAttrString(Node, "lineno", LineObj);
PyObject_SetAttrString(Node, "col_offset", ColObj);
PyObject_SetAttrString(Node, "end_lineno", EndLineObj);
PyObject_SetAttrString(Node, "end_col_offset", EndColObj);
}
Py_XDECREF(LineObj);
Py_XDECREF(ColObj);
Py_XDECREF(EndLineObj);
Py_XDECREF(EndColObj);
}
/* ================= Tokenizer ================= */
static int IsNameStart(int C) {
return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || C == '_';
}
static int IsNameChar(int C) {
return IsNameStart(C) || (C >= '0' && C <= '9');
}
static int IsDigit(int C) {
return C >= '0' && C <= '9';
}
static void NextToken(Parser *P) {
/* 跳过空白(不含换行) */
while (P->Pos < P->Len) {
char C = P->Src[P->Pos];
if (C == ' ' || C == '\t' || C == '\r') {
P->Pos++;
P->Col++;
} else {
break;
}
}
Token T;
T.Start = P->Src + P->Pos;
T.Len = 0;
T.Line = P->Line;
T.Col = P->Col;
if (P->Pos >= P->Len) {
T.Kind = TK_EOF;
P->Cur = T;
return;
}
char C = P->Src[P->Pos];
if (C == '\n') {
T.Kind = TK_NEWLINE;
T.Len = 1;
P->Pos++;
P->Line++;
P->Col = 0;
} else if (IsNameStart(C)) {
Py_ssize_t Start = P->Pos;
while (P->Pos < P->Len && IsNameChar(P->Src[P->Pos])) {
P->Pos++;
}
T.Kind = TK_NAME;
T.Len = P->Pos - Start;
P->Col += (int)T.Len;
} else if (IsDigit(C)) {
Py_ssize_t Start = P->Pos;
while (P->Pos < P->Len && (IsDigit(P->Src[P->Pos]) || P->Src[P->Pos] == '.')) {
P->Pos++;
}
T.Kind = TK_NUMBER;
T.Len = P->Pos - Start;
P->Col += (int)T.Len;
} else {
switch (C) {
case '=':
T.Kind = TK_EQUAL;
T.Len = 1;
P->Pos++;
P->Col++;
break;
case '(':
T.Kind = TK_LPAREN;
T.Len = 1;
P->Pos++;
P->Col++;
break;
case ')':
T.Kind = TK_RPAREN;
T.Len = 1;
P->Pos++;
P->Col++;
break;
default:
T.Kind = TK_EOF;
P->Error = 1;
break;
}
}
P->Cur = T;
}
/* ================= Parser ================= */
static PyObject *ParseExpression(Parser *P);
/* 原子表达式:数字常量 / 名字 */
static PyObject *ParsePrimary(Parser *P) {
if (P->Cur.Kind == TK_NUMBER) {
const char *Text = P->Cur.Start;
Py_ssize_t Len = P->Cur.Len;
int Line = P->Cur.Line;
int Col = P->Cur.Col;
int IsFloat = 0;
for (Py_ssize_t I = 0; I < Len; I++) {
if (Text[I] == '.') {
IsFloat = 1;
break;
}
}
PyObject *StrObj = PyUnicode_FromStringAndSize(Text, Len);
if (StrObj == NULL) {
P->Error = 1;
return NULL;
}
PyObject *ValObj;
if (IsFloat) {
ValObj = PyFloat_FromString(StrObj);
} else {
ValObj = PyLong_FromUnicodeObject(StrObj, 10);
}
Py_DECREF(StrObj);
if (ValObj == NULL) {
P->Error = 1;
return NULL;
}
PyObject *Args[2];
Args[0] = ValObj;
Args[1] = Py_None;
PyObject *Node = NodeMake(P, "Constant", Args, 2);
Py_DECREF(ValObj);
if (Node == NULL) {
return NULL;
}
NodePos(P, Node, Line, Col);
NextToken(P);
return Node;
}
if (P->Cur.Kind == TK_NAME) {
const char *Text = P->Cur.Start;
Py_ssize_t Len = P->Cur.Len;
int Line = P->Cur.Line;
int Col = P->Cur.Col;
PyObject *LoadCls = ClassGet(P, "Load");
if (LoadCls == NULL) {
return NULL;
}
PyObject *Ctx = PyObject_Vectorcall(LoadCls, NULL, 0, NULL);
PyObject *Id = PyUnicode_FromStringAndSize(Text, Len);
if (Ctx == NULL || Id == NULL) {
Py_XDECREF(Ctx);
Py_XDECREF(Id);
return NULL;
}
PyObject *Args[2];
Args[0] = Id;
Args[1] = Ctx;
PyObject *Node = NodeMake(P, "Name", Args, 2);
Py_DECREF(Ctx);
Py_DECREF(Id);
if (Node == NULL) {
return NULL;
}
NodePos(P, Node, Line, Col);
NextToken(P);
return Node;
}
P->Error = 1;
return NULL;
}
/* 表达式(阶段 0:仅原子表达式) */
static PyObject *ParseExpression(Parser *P) {
return ParsePrimary(P);
}
/* 语句:Name '=' expr → Assign;其余表达式 → Expr 语句 */
static PyObject *ParseStatement(Parser *P) {
int Line = P->Cur.Line;
int Col = P->Cur.Col;
if (P->Cur.Kind == TK_NAME) {
/* 向前看是否为赋值:Name '=' ... */
const char *Text = P->Cur.Start;
Py_ssize_t Len = P->Cur.Len;
NextToken(P);
if (P->Cur.Kind == TK_EQUAL) {
NextToken(P);
PyObject *Value = ParseExpression(P);
if (Value == NULL) {
return NULL;
}
PyObject *StoreCls = ClassGet(P, "Store");
if (StoreCls == NULL) {
Py_DECREF(Value);
return NULL;
}
PyObject *Ctx = PyObject_Vectorcall(StoreCls, NULL, 0, NULL);
PyObject *Id = PyUnicode_FromStringAndSize(Text, Len);
if (Ctx == NULL || Id == NULL) {
Py_XDECREF(Ctx);
Py_XDECREF(Id);
Py_DECREF(Value);
return NULL;
}
PyObject *TargetArgs[2];
TargetArgs[0] = Id;
TargetArgs[1] = Ctx;
PyObject *Target = NodeMake(P, "Name", TargetArgs, 2);
Py_DECREF(Ctx);
Py_DECREF(Id);
if (Target == NULL) {
Py_DECREF(Value);
return NULL;
}
NodePos(P, Target, Line, Col);
PyObject *Targets = PyList_New(1);
PyList_SetItem(Targets, 0, Target); /* 窃取引用 */
PyObject *AssignArgs[3];
AssignArgs[0] = Targets;
AssignArgs[1] = Value;
AssignArgs[2] = Py_None; /* type_comment */
PyObject *Node = NodeMake(P, "Assign", AssignArgs, 3);
Py_DECREF(Value);
if (Node == NULL) {
Py_DECREF(Targets);
return NULL;
}
NodePos(P, Node, Line, Col);
return Node;
}
/* 非赋值:Cur 已前进,直接用保存的文本构造 Load Name 表达式语句 */
PyObject *LoadCls = ClassGet(P, "Load");
if (LoadCls == NULL) {
return NULL;
}
PyObject *Ctx = PyObject_Vectorcall(LoadCls, NULL, 0, NULL);
PyObject *Id = PyUnicode_FromStringAndSize(Text, Len);
if (Ctx == NULL || Id == NULL) {
Py_XDECREF(Ctx);
Py_XDECREF(Id);
return NULL;
}
PyObject *NameArgs[2];
NameArgs[0] = Id;
NameArgs[1] = Ctx;
PyObject *NameNode = NodeMake(P, "Name", NameArgs, 2);
Py_DECREF(Ctx);
Py_DECREF(Id);
if (NameNode == NULL) {
return NULL;
}
NodePos(P, NameNode, Line, Col);
PyObject *ExprArgs[1];
ExprArgs[0] = NameNode;
PyObject *Node = NodeMake(P, "Expr", ExprArgs, 1);
Py_DECREF(NameNode);
if (Node == NULL) {
return NULL;
}
NodePos(P, Node, Line, Col);
return Node;
}
/* 一般表达式语句 */
PyObject *ExprVal = ParsePrimary(P);
if (ExprVal == NULL) {
return NULL;
}
PyObject *ExprArgs[1];
ExprArgs[0] = ExprVal;
PyObject *Node = NodeMake(P, "Expr", ExprArgs, 1);
Py_DECREF(ExprVal);
if (Node == NULL) {
return NULL;
}
NodePos(P, Node, Line, Col);
return Node;
}
/* 模块:语句序列 */
static PyObject *ParseModule(Parser *P) {
PyObject *Body = PyList_New(0);
if (Body == NULL) {
return NULL;
}
NextToken(P);
while (P->Cur.Kind != TK_EOF) {
if (P->Cur.Kind == TK_NEWLINE) {
NextToken(P);
continue;
}
PyObject *Stmt = ParseStatement(P);
if (Stmt == NULL) {
break;
}
PyList_Append(Body, Stmt);
Py_DECREF(Stmt);
}
PyObject *Ti = PyList_New(0);
if (Ti == NULL) {
Py_DECREF(Body);
return NULL;
}
PyObject *Args[2];
Args[0] = Body;
Args[1] = Ti;
PyObject *Mod = NodeMake(P, "Module", Args, 2);
return Mod;
}
/* ================= 模块入口 ================= */
static PyObject *VastC_Parse(PyObject *Self, PyObject *Args, PyObject *Kwargs) {
static char *KwList[] = {"source", "mode", NULL};
const char *Src = NULL;
Py_ssize_t Len = 0;
const char *Mode = "exec";
if (!PyArg_ParseTupleAndKeywords(Args, Kwargs, "s#|s:parse", KwList, &Src, &Len, &Mode)) {
return NULL;
}
Parser P;
P.Src = Src;
P.Len = Len;
P.Pos = 0;
P.Line = 1;
P.Col = 0;
P.Error = 0;
PyObject *Tree = ParseModule(&P);
if (Tree == NULL) {
if (P.Error) {
PyErr_SetString(PyExc_SyntaxError, "vast_c: 语法错误(阶段 0 仅支持赋值/名字/数字)");
}
return NULL;
}
if (strcmp(Mode, "exec") == 0) {
return Tree;
}
if (strcmp(Mode, "eval") == 0) {
/* 复用 vast.parse 的 eval 语义:Expose Expr 的 value 为 Expression 节点 */
PyObject *BodyAttr = PyObject_GetAttrString(Tree, "body");
Py_DECREF(Tree);
if (BodyAttr == NULL || PyList_GET_SIZE(BodyAttr) != 1) {
Py_XDECREF(BodyAttr);
PyErr_SetString(PyExc_SyntaxError, "vast_c: eval 模式需要单一表达式");
return NULL;
}
PyObject *Stmt = PyList_GetItem(BodyAttr, 0); /* borrowed */
PyObject *Value = PyObject_GetAttrString(Stmt, "value");
Py_DECREF(BodyAttr);
if (Value == NULL) {
return NULL;
}
PyObject *Args2[1];
Args2[0] = Value;
PyObject *ExprNode = NodeMake(&P, "Expression", Args2, 1);
Py_DECREF(Value);
return ExprNode;
}
Py_DECREF(Tree);
PyErr_SetString(PyExc_ValueError, "vast_c: 不支持的 mode");
return NULL;
}
static PyMethodDef VastC_Methods[] = {
{"parse", (PyCFunction)VastC_Parse, METH_VARARGS | METH_KEYWORDS,
"parse(source, mode='exec') -> vast.nodes 树(阶段 0 子集)"},
{NULL, NULL, 0, NULL},
};
static struct PyModuleDef VastC_Module = {
PyModuleDef_HEAD_INIT,
"vast_c",
"vast_c - C 版 Viper/Python 解析器(vast 加速层)",
-1,
VastC_Methods,
};
__declspec(dllexport) PyMODINIT_FUNC PyInit__parser(void) {
return PyModule_Create(&VastC_Module);
}