feat(tpc): 新增单目 * / & 运算符(Deref/AddrOf)AST 节点与 LLVM 翻译
This commit is contained in:
1 parent
d6150bd595
commit
0230385891
7 files changed
+67
-7
No files matched your search
@@ -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"
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)}'
|
||||
|
||||
|
||||
Reference in new issue
Block a user