From 02303858914821b85ae32ec755ac3ff3331b38b2 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 28 Aug 2026 07:34:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(tpc):=20=E6=96=B0=E5=A2=9E=E5=8D=95?= =?UTF-8?q?=E7=9B=AE=20*=20/=20&=20=E8=BF=90=E7=AE=97=E7=AC=A6=EF=BC=88Der?= =?UTF-8?q?ef/AddrOf=EF=BC=89AST=20=E8=8A=82=E7=82=B9=E4=B8=8E=20LLVM=20?= =?UTF-8?q?=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/ast/base.vp | 4 ++++ includes/ast/parser.vp | 9 ++++++-- lib/core/Handles/HandlesExprOps.py | 33 ++++++++++++++++++++++++++++ lib/core/Handles/HandlesExprUtils.py | 16 ++++++++++++-- lib/vast/ExprParser.py | 5 +++-- lib/vast/Nodes.py | 4 ++++ lib/vast/Unparser.py | 3 ++- 7 files changed, 67 insertions(+), 7 deletions(-) diff --git a/includes/ast/base.vp b/includes/ast/base.vp index dd2d38d..e4c0af8 100644 --- a/includes/ast/base.vp +++ b/includes/ast/base.vp @@ -138,6 +138,8 @@ class OpKind(t.CEnum): UAdd: t.State USub: t.State Invert: t.State + Deref: t.State + AddrOf: t.State # None NoneOp: t.State @@ -355,6 +357,8 @@ def _op_name(op: t.CInt) -> str: if op == OpKind.UAdd: return "UAdd" if op == OpKind.USub: return "USub" if op == OpKind.Invert: return "Invert" + if op == OpKind.Deref: return "Deref" + if op == OpKind.AddrOf: return "AddrOf" return "NoneOp" diff --git a/includes/ast/parser.vp b/includes/ast/parser.vp index e6584ee..a375bd1 100644 --- a/includes/ast/parser.vp +++ b/includes/ast/parser.vp @@ -771,8 +771,9 @@ def _parse_term(ps: Parser | t.CPtr) -> AST | t.CPtr: def _parse_factor(ps: Parser | t.CPtr) -> AST | t.CPtr: - """factor: '+' factor | '-' factor | '~' factor | power""" - if _match_op(ps, TokOp.Plus) or _match_op(ps, TokOp.Minus) or _match_op(ps, TokOp.Tilde): + """factor: '+' factor | '-' factor | '~' factor | '*' factor | '&' factor | power""" + if (_match_op(ps, TokOp.Plus) or _match_op(ps, TokOp.Minus) or _match_op(ps, TokOp.Tilde) + or _match_op(ps, TokOp.Star) or _match_op(ps, TokOp.Amp)): op_token: t.CInt = _cur_op(ps) lineno: t.CInt = _cur_lineno(ps) col: t.CInt = _cur_col(ps) @@ -783,6 +784,10 @@ def _parse_factor(ps: Parser | t.CPtr) -> AST | t.CPtr: ast_op = OpKind.USub elif op_token == TokOp.Tilde: ast_op = OpKind.Invert + elif op_token == TokOp.Star: + ast_op = OpKind.Deref + elif op_token == TokOp.Amp: + ast_op = OpKind.AddrOf node: AST | t.CPtr = UnaryOp(ps.pool, ast_op, operand) _set_pos(node, lineno, col, 0, 0) return node diff --git a/lib/core/Handles/HandlesExprOps.py b/lib/core/Handles/HandlesExprOps.py index df1f5ab..7f63659 100644 --- a/lib/core/Handles/HandlesExprOps.py +++ b/lib/core/Handles/HandlesExprOps.py @@ -248,6 +248,39 @@ class ExprOpsHandle(BaseHandle): return Gen.builder.neg(OperandVal, name="neg_result") elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)): return Gen.builder.fneg(OperandVal, name="fneg_result") + elif OpSymbol == '*': + # 单目解引用:*p = load(p),要求操作数是指针 + if not isinstance(OperandVal.type, ir.PointerType): + raise TypeError( + f"[fast-fail] 单目 '*' 解引用的操作数必须是指针类型," + f"实际为 {OperandVal.type}" + ) + return Gen._load(OperandVal, name="deref") + elif OpSymbol == '&': + # 单目取地址:&x 返回变量/字段/下标的地址(T*) + if isinstance(Node.operand, ast.Name): + VarName: str = Node.operand.id + if VarName in Gen.functions: + return Gen.functions[VarName] + if VarName in Gen.variables and Gen.variables[VarName] is not None: + var_ptr: ir.Value = Gen.variables[VarName] + if isinstance(var_ptr.type, ir.PointerType) and isinstance(var_ptr.type.pointee, ir.PointerType): + # T**:若 T 是 struct 类(变量语义即对象),返回对象指针 + if isinstance(var_ptr.type.pointee.pointee, ir.IdentifiedStructType): + return self.HandleExprLlvm(Node.operand) + return var_ptr + elif isinstance(Node.operand, ast.Attribute): + AttrPtr: ir.Value | None = self.Trans.ExprAttrHandle._get_attr_ptr(Node.operand) + if AttrPtr and isinstance(AttrPtr.type, ir.PointerType): + return AttrPtr + elif isinstance(Node.operand, ast.Subscript): + SubPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Node.operand) + if SubPtr and isinstance(SubPtr.type, ir.PointerType): + return SubPtr + raise TypeError( + f"[fast-fail] 单目 '&' 取地址的操作数必须是左值" + f"(Name/Attribute/Subscript),实际为 {type(Node.operand).__name__}" + ) return None def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None: diff --git a/lib/core/Handles/HandlesExprUtils.py b/lib/core/Handles/HandlesExprUtils.py index 6d6b42c..91cfb60 100644 --- a/lib/core/Handles/HandlesExprUtils.py +++ b/lib/core/Handles/HandlesExprUtils.py @@ -22,7 +22,10 @@ class ExprUtils: return OpMap.get(type(Op), None) def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None: - OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'} + OpMap: dict[type, str] = { + ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-', + ast.Deref: '*', ast.AddrOf: '&', + } return OpMap.get(type(Op), None) def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None: @@ -241,7 +244,16 @@ class ExprUtils: return ir.PointerType(ir.IntType(8)) return ir.IntType(32) elif isinstance(node, ast.UnaryOp): - return self._infer_expr_llvm_type_full(node.operand) + op_inner: ir.Type = self._infer_expr_llvm_type_full(node.operand) + if isinstance(node.op, ast.Deref): + # *p → pointee 类型 + if isinstance(op_inner, ir.PointerType): + return op_inner.pointee + return op_inner + if isinstance(node.op, ast.AddrOf): + # &x → T*(取地址即指针) + return ir.PointerType(op_inner) + return op_inner elif isinstance(node, ast.Subscript): val_type: ir.Type = self._infer_expr_llvm_type_full(node.value) if isinstance(val_type, ir.PointerType): diff --git a/lib/vast/ExprParser.py b/lib/vast/ExprParser.py index 7131d15..179598b 100644 --- a/lib/vast/ExprParser.py +++ b/lib/vast/ExprParser.py @@ -410,10 +410,11 @@ class ExprParserMixin(TokenStream): # ================================================================== def _ParseFactor(self) -> N.expr: tok: Token = self._Peek() - if tok.Type == OP and tok.Value in ('+', '-', '~'): + if tok.Type == OP and tok.Value in ('+', '-', '~', '*', '&'): self._Next() operand: N.expr = self._ParseFactor() - op_type: type = {'+': N.UAdd, '-': N.USub, '~': N.Invert}[tok.Value] + op_type: type = {'+': N.UAdd, '-': N.USub, '~': N.Invert, + '*': N.Deref, '&': N.AddrOf}[tok.Value] node: N.UnaryOp = N.UnaryOp(op=op_type(), operand=operand) self._FixLoc(node, tok) return node diff --git a/lib/vast/Nodes.py b/lib/vast/Nodes.py index 5c7a49e..13b96e1 100644 --- a/lib/vast/Nodes.py +++ b/lib/vast/Nodes.py @@ -164,6 +164,9 @@ _NODE_DEFS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = { 'Not': ((), ()), 'UAdd': ((), ()), 'USub': ((), ()), + # Viper 扩展:单目解引用/取地址(*x / &x) + 'Deref': ((), ()), + 'AddrOf': ((), ()), 'Eq': ((), ()), 'NotEq': ((), ()), 'Lt': ((), ()), @@ -285,6 +288,7 @@ _BASE_CLASS: dict[str, str] = { 'BitAnd': 'operator', 'FloorDiv': 'operator', # unaryop 'Invert': 'unaryop', 'Not': 'unaryop', 'UAdd': 'unaryop', 'USub': 'unaryop', + 'Deref': 'unaryop', 'AddrOf': 'unaryop', # boolop 'And': 'boolop', 'Or': 'boolop', # cmpop diff --git a/lib/vast/Unparser.py b/lib/vast/Unparser.py index 0de3389..fe08ce8 100644 --- a/lib/vast/Unparser.py +++ b/lib/vast/Unparser.py @@ -355,7 +355,8 @@ class Unparser: return f'{self._expr(node.left)} {op} {self._expr(node.right)}' def _UnaryOp(self, node: N.UnaryOp) -> str: - ops: dict[type, str] = {N.USub: '-', N.UAdd: '+', N.Not: 'not ', N.Invert: '~'} + ops: dict[type, str] = {N.USub: '-', N.UAdd: '+', N.Not: 'not ', N.Invert: '~', + N.Deref: '*', N.AddrOf: '&'} op: str = ops.get(type(node.op), '?') return f'{op}{self._expr(node.operand)}'