from pyrser import parsing, meta
Storages = meta.enum('AUTO', 'REGISTER', 'TYPEDEF',
'STATIC', 'EXTERN', 'INLINE',
'VIRTUAL', 'EXPLICIT',
'FORCEINLINE', 'THREAD')
Qualifiers = meta.enum('AUTO', 'CONST', 'VOLATILE', 'RESTRICT',
'W64', 'STDCALL', 'CDECL',
'PTR32', 'PTR64', 'FASTCALL')
Specifiers = meta.enum('AUTO', 'STRUCT', 'UNION', 'ENUM', 'LONG',
'LONGLONG', 'SHORT')
Signs = meta.enum('AUTO', 'SIGNED', 'UNSIGNED')
# EXPRESSION PART
[docs]class Expr(parsing.Node):
"""All expression"""
[docs]class Func(Expr):
"""For almost everything"""
[docs] def __init__(self, call_expr: Expr, params: list):
Expr.__init__(self)
self.call_expr = call_expr
self.params = params
[docs]class BlockInit(Expr):
"""Initializer Block Expression"""
[docs] def __init__(self, body: [Expr]):
self.body = body
[docs]class BlockExpr(Expr):
"""Compound Block Expression"""
[docs] def __init__(self, body: [Expr]):
self.body = body
[docs]class Unary(Func):
"""For unary operator"""
[docs]class Paren(Unary):
"""For () expression"""
[docs]class Array(Unary):
"""For [] expression"""
[docs]class Dot(Unary):
"""For . expression"""
[docs]class Arrow(Unary):
"""For -> expression"""
[docs]class Post(Unary):
"""For post{inc,dec} expression"""
[docs]class Sizeof(Unary):
"""For sizeof expr/type expression"""
[docs]class Binary(Func):
"""For binary operator"""
[docs]class Cast(Binary):
"""For cast operator"""
[docs]class Range(Binary):
"""For range expression"""
[docs]class Ternary(Func):
"""For ternary operator"""
[docs]class Terminal(Expr):
"""For Terminal expression"""
[docs] def __init__(self, value: str):
Expr.__init__(self)
self.value = value
[docs]class Id(Terminal):
"""Terminal Id"""
[docs]class Literal(Terminal):
"""Terminal Literal"""
[docs]class Raw(Terminal):
"""Terminal Raw"""
# DECLARATION PART
[docs]class Enumerator(parsing.Node):
"""Enumerator A=x in enums"""
[docs] def __init__(self, ident: str, expr: Expr):
self.ident = ident
self.expr = expr
[docs]class DeclType(parsing.Node):
"""For type in declaration"""
[docs] def __init__(self):
self._decltype = None
[docs] def link(self, t: 'DeclType'=None):
if t is not None:
if not isinstance(t, DeclType):
raise Exception("add only C type declarator")
self._decltype = t
return self._decltype
[docs] def push(self, t: 'DeclType'=None):
if t is not None:
if not isinstance(t, DeclType):
raise Exception("add only C type declarator")
old = self._decltype
self._decltype = t
self._decltype.link(old)
return self._decltype
[docs]class PointerType(DeclType):
"""For pointer in declaration"""
[docs]class ArrayType(DeclType):
"""For array in declaration"""
[docs] def __init__(self, expr=None):
DeclType.__init__(self)
self._expr = expr
@property
def expr(self):
return self._expr
[docs]class ParenType(DeclType):
"""For parenthesis in declaration"""
[docs] def __init__(self, params=None):
DeclType.__init__(self)
if params is None:
params = []
self._params = params
@property
def params(self):
return self._params
[docs]class QualType(DeclType):
"""For qualifier in declaration"""
[docs] def __init__(self, qualifier: Qualifiers=Qualifiers.AUTO):
DeclType.__init__(self)
# qualifier in (auto, const, volatile, restrict)
self._qualifier = qualifier
[docs]class AttrType(DeclType):
"""For attribute specifier in declaration"""
[docs] def __init__(self, raw: str):
DeclType.__init__(self)
# fix
self._attr = raw.rstrip(' ')
[docs]class CType(parsing.Node):
"""Base for primary/func"""
[docs] def __init__(self):
parsing.Node.__init__(self)
self._decltype = None
# only one storage by declaration
# i.e: auto, register, typedef, static, extern, ...
self._storage = Storages.AUTO
# only one specifier by declaration
# i.e: auto, short, long, struct, union, enum, ...
self._specifier = Specifiers.AUTO
[docs] def copy(self):
import copy
theclone = copy.copy(self)
theclone._decltype = None
return theclone
[docs] def link(self, t: DeclType=None):
if t is not None:
if not isinstance(t, DeclType):
raise Exception("add only C type declarator")
self._decltype = t
return self._decltype
[docs] def push(self, t: DeclType=None):
if t is not None:
if not isinstance(t, DeclType):
raise Exception("add only C type declarator")
old = self._decltype
self._decltype = t
self._decltype.link(old)
return self._decltype
[docs]class PrimaryType(CType):
"""For primary type in declaration"""
[docs] def __init__(self, identifier: str):
CType.__init__(self)
# identifier (void, char, int, float, double, typedefname)
self._identifier = identifier
@property
def identifier(self):
return self._identifier
[docs]class ComposedType(CType):
"""For composed type in declaration"""
[docs] def __init__(self, identifier: str):
CType.__init__(self)
# identifier (name of the struct/union/enum)
self._identifier = identifier
# if struct/union then self.fields = []
# if enum then self.enums = []
@property
def identifier(self):
return self._identifier
[docs]class FuncType(PrimaryType):
"""For function in declaration"""
[docs] def __init__(self, identifier: str, params=[], decltype=None):
PrimaryType.__init__(self, identifier)
self.opened = True
if decltype is not None:
self._decltype = decltype
self._params = params
@property
def params(self):
return self._params
# helper to create a CType from previous one
[docs]def makeCType(declspecifier: str, ctype=None):
from cnorm.parsing.expression import Idset
if ctype is None:
ctype = PrimaryType('int')
if Idset[declspecifier] == "type":
ctype._identifier = declspecifier
if Idset[declspecifier] == "storage":
cleantxt = declspecifier.strip("_")
ctype._storage = Storages.map[cleantxt.upper()]
if Idset[declspecifier] == "qualifier":
cleantxt = declspecifier.strip("_")
ctype.link(QualType(Qualifiers.map[cleantxt.upper()]))
if Idset[declspecifier] == "funspecifier":
cleantxt = declspecifier.strip("_")
ctype._storage = Storages.map[cleantxt.upper()]
if Idset[declspecifier] == "sign_unsigned":
cleantxt = declspecifier.strip("_")
ctype._sign = Signs.map[cleantxt.upper()]
if Idset[declspecifier] == "sign_signed":
cleantxt = declspecifier.strip("_")
ctype._sign = Signs.map[cleantxt.upper()]
if Idset[declspecifier] == "specifier_block":
cleantxt = declspecifier.strip("_")
ctype._specifier = Specifiers.map[cleantxt.upper()]
if Idset[declspecifier] == "specifier_enum":
cleantxt = declspecifier.strip("_")
ctype._specifier = Specifiers.map[cleantxt.upper()]
if Idset[declspecifier] == "specifier_size":
cleantxt = declspecifier.strip("_")
ctype._specifier = Specifiers.map[cleantxt.upper()]
if Idset[declspecifier] == "specifier_size_size":
cleantxt = declspecifier.strip("_")
if ctype._specifier == Specifiers.AUTO:
ctype._specifier = Specifiers.map[cleantxt.upper()]
else:
ctype._specifier = Specifiers.LONGLONG
return ctype
[docs]class Decl(Expr):
"""For basic declaration
A declaration contains the following attributes:
* _name: name of the declaration
* _ctype: the CType describing the type of the declaration
* _assign_expr: when the declaration have a value
* _colon_expr: When it's a bitfield
* body: when it's function definition
"""
[docs] def __init__(self, name: str, ct=None):
if ct is None:
ct = PrimaryType('int')
Expr.__init__(self)
self._name = name
self._ctype = ct
@property
def ctype(self) -> CType:
return self._ctype
[docs] def assign_expr(self, expr=None):
if not hasattr(self, '_assign_expr'):
self._assign_expr = None
if expr is not None:
self._assign_expr = expr
return self._assign_expr
[docs] def colon_expr(self, expr=None):
if not hasattr(self, '_colon_expr'):
self._colon_expr = None
if expr is not None:
self._colon_expr = expr
return self._colon_expr
# STATEMENT PART
[docs]class Stmt(parsing.Node):
"""For statement"""
[docs]class ExprStmt(Stmt):
"""Expression statement"""
[docs] def __init__(self, expr: Expr):
parsing.Node.__init__(self)
self.expr = expr
[docs]class BlockStmt(Stmt):
"""Block statement"""
[docs] def __init__(self, body: [ExprStmt]):
parsing.Node.__init__(self)
self.body = body
[docs] def func(self, name: str):
"""return the first func defined named name"""
for f in self.body:
if (hasattr(f, '_ctype')
and isinstance(f._ctype, FuncType)
and f._name == name):
return f
[docs] def var(self, name: str):
"""return the first var instancied named name"""
for f in self.body:
if (hasattr(f, '_ctype')
and not isinstance(f._ctype, FuncType)
and f._name == name):
return f
[docs] def type(self, name: str):
"""return the first complete definition of type 'name'"""
for f in self.body:
if (hasattr(f, '_ctype')
and f._ctype._storage == Storages.TYPEDEF
and f._name == name):
return f
[docs] def declfuncs(self, name: str):
"""generator on all declaration of function 'name'"""
for f in self.body:
if (hasattr(f, '_ctype')
and isinstance(f._ctype, FuncType)
and f._name == name):
yield f
[docs] def declvars(self, name: str):
"""generator on all declaration of variable 'name'"""
for f in self.body:
if (hasattr(f, '_ctype')
and not isinstance(f._ctype, FuncType)
and f._name == name):
yield f
[docs] def decltypes(self, name: str):
"""generator on all declaration of type 'name'"""
for f in self.body:
if (hasattr(f, '_ctype')
and f._ctype._storage == Storages.TYPEDEF
and f._name == name):
yield f
[docs] def declallfuncs(self):
"""generator on all declaration of function"""
for f in self.body:
if (hasattr(f, '_ctype')
and isinstance(f._ctype, FuncType)):
yield f
[docs] def declallvars(self):
"""generator on all declaration of variable"""
for f in self.body:
if (hasattr(f, '_ctype')
and not isinstance(f._ctype, FuncType)):
yield f
[docs] def declalltypes(self):
"""generator on all declaration of type"""
for f in self.body:
if (hasattr(f, '_ctype')
and f._ctype._storage == Storages.TYPEDEF):
yield f
[docs]class RootBlockStmt(BlockStmt):
"""Root Block statement"""
[docs] def __init__(self, body: [ExprStmt]):
BlockStmt.__init__(self, body)
from collections import ChainMap
self.types = ChainMap()
[docs]class Label(Stmt):
"""Label statement"""
[docs] def __init__(self, value: str):
Stmt.__init__(self)
self.value = value
[docs]class Branch(Label):
"""branch statement"""
[docs] def __init__(self, value: str, expr: Expr):
Label.__init__(self, value)
self.expr = expr
[docs]class Case(Branch):
"""Case statement"""
[docs] def __init__(self, expr: Expr):
Branch.__init__(self, "case", expr)
[docs]class Return(Branch):
"""Return statement"""
[docs] def __init__(self, expr: Expr):
Branch.__init__(self, "return", expr)
[docs]class Goto(Branch):
"""Goto statement"""
[docs] def __init__(self, expr: Expr):
Branch.__init__(self, "goto", expr)
[docs]class LoopControl(Label):
"""loop control statement"""
[docs]class Break(LoopControl):
"""break statement"""
[docs] def __init__(self):
Label.__init__(self, "break")
[docs]class Continue(LoopControl):
"""continue statement"""
[docs] def __init__(self):
Label.__init__(self, "continue")
[docs]class Conditional(Stmt):
"""Conditional statement"""
[docs] def __init__(self, condition: Expr):
Stmt.__init__(self)
self.condition = condition
[docs]class If(Conditional):
"""If statement"""
[docs] def __init__(self, condition: Expr, thencond: Stmt, elsecond: Stmt=None):
Conditional.__init__(self, condition)
self.thencond = thencond
self.elsecond = elsecond
[docs]class While(Conditional):
"""While statement"""
[docs] def __init__(self, condition: Expr, body: Stmt):
Conditional.__init__(self, condition)
self.body = body
[docs]class Switch(Conditional):
"""Switch statement"""
[docs] def __init__(self, condition: Expr, body: Stmt):
Conditional.__init__(self, condition)
self.body = body
[docs]class Do(Conditional):
"""Do statement"""
[docs] def __init__(self, condition: Expr, body: Stmt):
Conditional.__init__(self, condition)
self.body = body
[docs]class For(Stmt):
"""For statement"""
[docs] def __init__(self, init: Expr, condition: Expr,
increment: Expr, body: Stmt):
Stmt.__init__(self)
self.init = init
self.condition = condition
self.increment = increment
self.body = body