Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Franck Pommereau
/
cct
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Issues
0
Wiki
Network
Create a new issue
Commits
Authored by
Franck Pommereau
2018-04-27 18:01:07 +0200
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
1169f4439cfe8d6d99cc6d0e44164b8222ead605
1169f443
1 parent
f5f5e292
started to replace parser
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
673 additions
and
421 deletions
cctlib/cast.py
cctlib/cparse.py
cctlib/cttc.py
cctlib/cvisitors.py
cctlib/parser.py
cctlib/cast.py
0 → 100644
View file @
1169f44
# cast.py: extracted from cparse.py by Franck Pommereau (2018)
# ---------------------------------------------------------------
# cparse.py
#
# Atul Varma
# Python C Compiler - Parser
# $Id: cparse.py,v 1.2 2004/05/27 16:25:08 varmaa Exp $
# ---------------------------------------------------------------
# ---------------------------------------------------------------
# ABSTRACT SYNTAX TREE - NODES
# ---------------------------------------------------------------
class
Node
:
"Base class for all nodes on the abstract syntax tree."
def
__init__
(
self
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
)
:
self
.
lineno
=
lineno
self
.
colno
=
colno
self
.
filename
=
filename
def
loc
(
self
)
:
return
"
%
s:
%
s:
%
s"
%
(
self
.
filename
,
self
.
lineno
,
self
.
colno
)
def
is_null
(
self
):
"""Returns whether the node represents a null node."""
return
0
def
is_const
(
self
):
"""Returns whether the node is a constant numeric number
(e.g., "5")."""
return
0
def
has_address
(
self
):
"""Returns whether the node has an address (i.e., is a valid
lvalue)."""
return
hasattr
(
self
,
"has_addr"
)
def
set_has_address
(
self
):
"""Tells the node that has an address (is an lvalue).
Ultimately, the address of the node should be placed in the
output_addr attribute."""
self
.
has_addr
=
1
self
.
output_addr
=
0
def
calculate
(
self
):
"""Calculates the constant numeric value of the node and
its subnodes, if one exists. For instance, if a node
corresponds to the expression "5+3", then this method
would return 8."""
return
None
def
accept
(
self
,
visitor
):
"""Accept method for visitor classes (see cvisitor.py)."""
return
self
.
_accept
(
self
.
__class__
,
visitor
)
def
_accept
(
self
,
klass
,
visitor
):
"""Accept implementation. This is actually a recursive
function that dynamically figures out which visitor method to
call. This is done by appending the class' name to 'v', so if
the node class is called MyNode, then this method tries
calling visitor.vMyNode(). If that node doesn't exist, then
it recursively attempts to call the visitor method
corresponding to the class' superclass (e.g.,
visitor.vNode())."""
visitor_method
=
getattr
(
visitor
,
"v
%
s"
%
klass
.
__name__
,
None
)
if
visitor_method
==
None
:
bases
=
klass
.
__bases__
last
=
None
for
i
in
bases
:
last
=
self
.
_accept
(
i
,
visitor
)
return
last
else
:
return
visitor_method
(
self
)
class
NullNode
(
Node
):
"""A null node is like a null terminator for AST's."""
def
__init__
(
self
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
type
=
'void'
def
is_null
(
self
):
return
1
class
ArrayExpression
(
Node
):
"""This is an expression with array notation, like "a[5+b]"."""
def
__init__
(
self
,
expr
,
index
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
expr
=
expr
self
.
index
=
index
class
StringLiteral
(
Node
):
"""A string literal, e.g. the string "Hello World" in
printf("Hello World")."""
def
__init__
(
self
,
str
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
_str
=
str
self
.
type
=
PointerType
(
BaseType
(
'char'
))
def
append_str
(
self
,
str
):
self
.
_str
+=
str
def
get_str
(
self
):
return
self
.
_str
def
get_sanitized_str
(
self
):
"""Returns a 'sanitized' version of the string, converting
all carriage returns to '
\n
' symbols, etc."""
return
self
.
_str
.
replace
(
'
\n
'
,
'
\\
n'
)
class
Id
(
Node
):
"""An identifier, which can correspond to the name of
a function, variable, etc..."""
def
__init__
(
self
,
name
,
lineno
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
name
=
name
class
Const
(
Node
):
"""A numeric constant (i.e., an integral literal), such as
the number 5."""
def
__init__
(
self
,
value
,
type
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
value
=
value
self
.
type
=
type
def
calculate
(
self
):
return
self
.
value
def
is_const
(
self
):
return
1
class
Unaryop
(
Node
):
"""Any generic unary operator. This is an abstract base class."""
def
__init__
(
self
,
node
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
expr
=
node
class
Negative
(
Unaryop
):
"""A negative unary operator, e.g. '-5'."""
def
calculate
(
self
):
val
=
self
.
expr
.
calculate
()
if
val
is
not
None
:
return
-
val
return
None
class
Pointer
(
Unaryop
):
"""A pointer dereference, e.g. '*a'."""
pass
class
AddrOf
(
Unaryop
):
"""An address-of operator, e.g. '&a'."""
pass
class
Binop
(
Node
):
"""Any binary operator, such as that for arithmetic operations
(+/-/*), assignment operations (=/+=/-=), and so forth."""
# List of assignment operators.
ASSIGN_OPS
=
[
'='
,
'+='
,
'-='
]
def
__init__
(
self
,
left
,
right
,
op
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
left
=
left
self
.
right
=
right
self
.
op
=
op
def
calculate
(
self
):
left
=
self
.
left
.
calculate
()
right
=
self
.
right
.
calculate
()
if
left
is
not
None
and
right
is
not
None
:
return
int
(
eval
(
"
%
d
%
s
%
d"
%
(
left
,
self
.
op
,
right
)))
else
:
return
None
class
IfStatement
(
Node
):
"""An if/then/else statement."""
def
__init__
(
self
,
expr
,
then_stmt
,
else_stmt
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
expr
=
expr
self
.
then_stmt
=
then_stmt
self
.
else_stmt
=
else_stmt
class
BreakStatement
(
Node
):
"""A break statement (used while in a loop structure to bust out
of it)."""
pass
class
ContinueStatement
(
Node
):
"""A continue statement (used while in a loop structure to bust
back to the beginning of it)."""
pass
class
ReturnStatement
(
Node
):
"""A return statement, used to exit a function and optionally
return a value."""
def
__init__
(
self
,
expr
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
expr
=
expr
class
ForLoop
(
Node
):
"""A for loop."""
def
__init__
(
self
,
begin_stmt
,
expr
,
end_stmt
,
stmt
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
expr
=
expr
self
.
stmt
=
stmt
self
.
begin_stmt
=
begin_stmt
self
.
end_stmt
=
end_stmt
class
WhileLoop
(
Node
):
"""A while loop."""
def
__init__
(
self
,
expr
,
stmt
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
expr
=
expr
self
.
stmt
=
stmt
class
NodeList
(
Node
):
"""A list of nodes. This is an abstract base class."""
def
__init__
(
self
,
node
=
None
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
nodes
=
[]
if
node
is
not
None
:
self
.
nodes
.
append
(
node
)
def
add
(
self
,
node
):
self
.
nodes
.
append
(
node
)
class
ArgumentList
(
NodeList
):
"""A list of arguments for a function expression. e.g., the list
'5,2,3' in 'a = my_func(5,2,3)'."""
pass
class
ParamList
(
NodeList
):
"""A list of parameters for a function prototype, e.g. the list
'int a, char b, char c' in 'int my_func(int a, char b, char c)'."""
def
__init__
(
self
,
node
=
None
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
NodeList
.
__init__
(
self
,
node
,
lineno
,
colno
,
filename
)
self
.
has_ellipsis
=
0
class
StatementList
(
NodeList
):
"""Any list of statements. For instance, this can be the list of
statements in a function body."""
pass
class
TranslationUnit
(
NodeList
):
"""A list of nodes representing the program itself."""
pass
class
DeclarationList
(
NodeList
):
"""A list of variable declarations, such as the ones put
at the beginning of a compound statement (e.g., the beginning
of a function body)."""
pass
class
FunctionExpression
(
Node
):
"""An execution of a function, e.g. 'my_func(a,b,c)'."""
def
__init__
(
self
,
function
,
arglist
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
function
=
function
self
.
arglist
=
arglist
class
CompoundStatement
(
Node
):
"""A compound statement, e.g. '{ int i; i += 1; }'."""
def
__init__
(
self
,
declaration_list
,
statement_list
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
declaration_list
=
declaration_list
self
.
statement_list
=
statement_list
class
FunctionDefn
(
Node
):
"""A node representing a function definition (its declaration
and body)."""
def
__init__
(
self
,
declaration
,
body
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
self
.
type
=
declaration
.
type
self
.
name
=
declaration
.
name
self
.
extern
=
declaration
.
extern
self
.
static
=
declaration
.
static
self
.
body
=
body
class
Declaration
(
Node
):
"""A node representing a declaration of a function or
variable."""
def
__init__
(
self
,
name
,
type
=
None
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
if
type
is
None
:
type
=
NullNode
()
self
.
extern
=
0
self
.
static
=
0
self
.
type
=
type
self
.
name
=
name
self
.
is_used
=
0
def
set_base_type
(
self
,
type
):
if
self
.
type
.
is_null
():
self
.
type
=
type
else
:
self
.
type
.
set_base_type
(
type
)
def
add_type
(
self
,
type
):
type
.
set_base_type
(
self
.
type
)
self
.
type
=
type
# ---------------------------------------------------------------
# ABSTRACT SYNTAX TREE - TYPE SYSTEM
# ---------------------------------------------------------------
class
Type
(
Node
):
"""A node representing the type of another node. For instance,
the Binop node representing '5 + a', where a is an int, will have
a Type node associated with it that represents the fact that
the result of the Binop is an int.
Types can also be nested, so that for instance you can have
a type like 'pointer(pointer(int))' which represents a
double-pointer to an int.
This is an abstract base class."""
def
__init__
(
self
,
child
=
None
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Node
.
__init__
(
self
,
lineno
,
colno
,
filename
)
if
child
is
None
:
child
=
NullNode
()
self
.
child
=
child
def
set_base_type
(
self
,
type
):
"""Set the base (innermost) type of a type. For instance,
calling this with a pointer(int) type on a pointer() type
will give you a pointer(pointer(int))."""
if
self
.
child
.
is_null
():
self
.
child
=
type
else
:
self
.
child
.
set_base_type
(
type
)
def
get_string
(
self
):
"""Return a string corresponding to the type, e.g.
'pointer(pointer(int))'."""
raise
NotImplementedError
()
def
get_outer_string
(
self
):
"""Return only the outermost type of a type. e.g.,
calling this on a pointer(pointer(int)) type will
return 'pointer'."""
raise
NotImplementedError
()
def
is_function
(
self
):
"""Returns whether or not this type represents a
function."""
return
0
class
BaseType
(
Type
):
"""A base type representing ints, chars, etc..."""
def
__init__
(
self
,
type_str
,
child
=
None
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Type
.
__init__
(
self
,
child
,
lineno
,
colno
,
filename
)
self
.
type_str
=
type_str
def
get_string
(
self
):
return
self
.
type_str
def
get_outer_string
(
self
):
return
self
.
type_str
class
FunctionType
(
Type
):
"""A type representing a function (for function prototypes and
function calls)."""
def
__init__
(
self
,
params
=
None
,
child
=
None
,
lineno
=
0
,
colno
=
0
,
filename
=
"<string>"
):
Type
.
__init__
(
self
,
child
,
lineno
,
colno
,
filename
)
if
(
params
==
None
):
params
=
NullNode
()
self
.
params
=
params
def
get_string
(
self
):
param_str
=
""
for
param
in
self
.
params
.
nodes
:
param_str
+=
","
+
param
.
type
.
get_string
()
return
"function(
%
s)->
%
s"
%
(
param_str
[
1
:],
self
.
child
.
get_string
())
def
get_outer_string
(
self
):
return
'function'
def
is_function
(
self
):
return
1
def
get_return_type
(
self
):
"""Returns the return type of the function. Internally,
this is stored as the nested type within the function."""
return
self
.
child
def
get_params
(
self
):
"""Returns the list of parameters for the function."""
return
self
.
params
class
PointerType
(
Type
):
"""A type representing a pointer to another (nested) type."""
def
get_string
(
self
):
return
"pointer(
%
s)"
%
self
.
child
.
get_string
()
def
get_outer_string
(
self
):
return
'pointer'
cctlib/cparse.py
View file @
1169f44
...
...
@@ -10,130 +10,8 @@
import
ply.yacc
as
yacc
from
.clex
import
tokens
# ---------------------------------------------------------------
# ABSTRACT SYNTAX TREE - NODES
# ---------------------------------------------------------------
class
Node
:
"Base class for all nodes on the abstract syntax tree."
def
is_null
(
self
):
"""Returns whether the node represents a null node."""
return
0
def
is_const
(
self
):
"""Returns whether the node is a constant numeric number
(e.g., "5")."""
return
0
def
has_address
(
self
):
"""Returns whether the node has an address (i.e., is a valid
lvalue)."""
return
hasattr
(
self
,
"has_addr"
)
def
set_has_address
(
self
):
"""Tells the node that has an address (is an lvalue).
Ultimately, the address of the node should be placed in the
output_addr attribute."""
self
.
has_addr
=
1
self
.
output_addr
=
0
def
calculate
(
self
):
"""Calculates the constant numeric value of the node and
its subnodes, if one exists. For instance, if a node
corresponds to the expression "5+3", then this method
would return 8."""
return
None
def
accept
(
self
,
visitor
):
"""Accept method for visitor classes (see cvisitor.py)."""
return
self
.
_accept
(
self
.
__class__
,
visitor
)
def
_accept
(
self
,
klass
,
visitor
):
"""Accept implementation. This is actually a recursive
function that dynamically figures out which visitor method to
call. This is done by appending the class' name to 'v', so if
the node class is called MyNode, then this method tries
calling visitor.vMyNode(). If that node doesn't exist, then
it recursively attempts to call the visitor method
corresponding to the class' superclass (e.g.,
visitor.vNode())."""
visitor_method
=
getattr
(
visitor
,
"v
%
s"
%
klass
.
__name__
,
None
)
if
visitor_method
==
None
:
bases
=
klass
.
__bases__
last
=
None
for
i
in
bases
:
last
=
self
.
_accept
(
i
,
visitor
)
return
last
else
:
return
visitor_method
(
self
)
class
NullNode
(
Node
):
"""A null node is like a null terminator for AST's."""
def
__init__
(
self
):
self
.
type
=
'void'
def
is_null
(
self
):
return
1
class
ArrayExpression
(
Node
):
"""This is an expression with array notation, like "a[5+b]"."""
def
__init__
(
self
,
expr
,
index
):
self
.
expr
=
expr
self
.
index
=
index
class
StringLiteral
(
Node
):
"""A string literal, e.g. the string "Hello World" in
printf("Hello World")."""
def
__init__
(
self
,
str
):
self
.
_str
=
str
self
.
type
=
PointerType
(
BaseType
(
'char'
))
def
append_str
(
self
,
str
):
self
.
_str
+=
str
def
get_str
(
self
):
return
self
.
_str
def
get_sanitized_str
(
self
):
"""Returns a 'sanitized' version of the string, converting
all carriage returns to '
\n
' symbols, etc."""
return
self
.
_str
.
replace
(
'
\n
'
,
'
\\
n'
)
class
Id
(
Node
):
"""An identifier, which can correspond to the name of
a function, variable, etc..."""
def
__init__
(
self
,
name
,
lineno
):
self
.
name
=
name
self
.
lineno
=
lineno
class
Const
(
Node
):
"""A numeric constant (i.e., an integral literal), such as
the number 5."""
def
__init__
(
self
,
value
,
type
):
self
.
value
=
value
self
.
type
=
type
def
calculate
(
self
):
return
self
.
value
def
is_const
(
self
):
return
1
from
.clex
import
tokens
# needed by yacc.yacc()
from
.cast
import
*
# the content of cast.py was originally here
def
_get_calculated
(
node
):
"""Attempts to calculate the numeric value of the expression,
...
...
@@ -142,296 +20,12 @@ def _get_calculated(node):
this function just returns the node unmodified."""
result
=
node
.
calculate
()
if
result
!=
None
:
if
result
is
not
None
:
result
=
int
(
result
)
return
Const
(
result
,
BaseType
(
'int'
))
else
:
return
node
class
Unaryop
(
Node
):
"""Any generic unary operator. This is an abstract base class."""
def
__init__
(
self
,
node
):
self
.
expr
=
node
class
Negative
(
Unaryop
):
"""A negative unary operator, e.g. '-5'."""
def
calculate
(
self
):
val
=
self
.
expr
.
calculate
()
if
val
!=
None
:
return
-
val
return
None
class
Pointer
(
Unaryop
):
"""A pointer dereference, e.g. '*a'."""
pass
class
AddrOf
(
Unaryop
):
"""An address-of operator, e.g. '&a'."""
pass
class
Binop
(
Node
):
"""Any binary operator, such as that for arithmetic operations
(+/-/*), assignment operations (=/+=/-=), and so forth."""
# List of assignment operators.
ASSIGN_OPS
=
[
'='
,
'+='
,
'-='
]
def
__init__
(
self
,
left
,
right
,
op
):
self
.
left
=
left
self
.
right
=
right
self
.
op
=
op
def
calculate
(
self
):
left
=
self
.
left
.
calculate
()
right
=
self
.
right
.
calculate
()
if
left
!=
None
and
right
!=
None
:
return
int
(
eval
(
"
%
d
%
s
%
d"
%
(
left
,
self
.
op
,
right
)))
else
:
return
None
class
IfStatement
(
Node
):
"""An if/then/else statement."""
def
__init__
(
self
,
expr
,
then_stmt
,
else_stmt
):
self
.
expr
=
expr
self
.
then_stmt
=
then_stmt
self
.
else_stmt
=
else_stmt
class
BreakStatement
(
Node
):
"""A break statement (used while in a loop structure to bust out
of it)."""
pass
class
ContinueStatement
(
Node
):
"""A continue statement (used while in a loop structure to bust
back to the beginning of it)."""
pass
class
ReturnStatement
(
Node
):
"""A return statement, used to exit a function and optionally
return a value."""
def
__init__
(
self
,
expr
):
self
.
expr
=
expr
class
ForLoop
(
Node
):
"""A for loop."""
def
__init__
(
self
,
begin_stmt
,
expr
,
end_stmt
,
stmt
):
self
.
expr
=
expr
self
.
stmt
=
stmt
self
.
begin_stmt
=
begin_stmt
self
.
end_stmt
=
end_stmt
class
WhileLoop
(
Node
):
"""A while loop."""
def
__init__
(
self
,
expr
,
stmt
):
self
.
expr
=
expr
self
.
stmt
=
stmt
class
NodeList
(
Node
):
"""A list of nodes. This is an abstract base class."""
def
__init__
(
self
,
node
=
None
):
self
.
nodes
=
[]
if
node
!=
None
:
self
.
nodes
.
append
(
node
)
def
add
(
self
,
node
):
self
.
nodes
.
append
(
node
)
class
ArgumentList
(
NodeList
):
"""A list of arguments for a function expression. e.g., the list
'5,2,3' in 'a = my_func(5,2,3)'."""
pass
class
ParamList
(
NodeList
):
"""A list of parameters for a function prototype, e.g. the list
'int a, char b, char c' in 'int my_func(int a, char b, char c)'."""
def
__init__
(
self
,
node
=
None
):
NodeList
.
__init__
(
self
,
node
)
self
.
has_ellipsis
=
0
class
StatementList
(
NodeList
):
"""Any list of statements. For instance, this can be the list of
statements in a function body."""
pass
class
TranslationUnit
(
NodeList
):
"""A list of nodes representing the program itself."""
pass
class
DeclarationList
(
NodeList
):
"""A list of variable declarations, such as the ones put
at the beginning of a compound statement (e.g., the beginning
of a function body)."""
pass
class
FunctionExpression
(
Node
):
"""An execution of a function, e.g. 'my_func(a,b,c)'."""
def
__init__
(
self
,
function
,
arglist
):
self
.
function
=
function
self
.
arglist
=
arglist
class
CompoundStatement
(
Node
):
"""A compound statement, e.g. '{ int i; i += 1; }'."""
def
__init__
(
self
,
declaration_list
,
statement_list
):
self
.
declaration_list
=
declaration_list
self
.
statement_list
=
statement_list
class
FunctionDefn
(
Node
):
"""A node representing a function definition (its declaration
and body)."""
def
__init__
(
self
,
declaration
,
body
):
self
.
type
=
declaration
.
type
self
.
name
=
declaration
.
name
self
.
extern
=
declaration
.
extern
self
.
static
=
declaration
.
static
self
.
body
=
body
class
Declaration
(
Node
):
"""A node representing a declaration of a function or
variable."""
def
__init__
(
self
,
name
,
type
=
None
):
if
type
==
None
:
type
=
NullNode
()
self
.
extern
=
0
self
.
static
=
0
self
.
type
=
type
self
.
name
=
name
self
.
is_used
=
0
def
set_base_type
(
self
,
type
):
if
self
.
type
.
is_null
():
self
.
type
=
type
else
:
self
.
type
.
set_base_type
(
type
)
def
add_type
(
self
,
type
):
type
.
set_base_type
(
self
.
type
)
self
.
type
=
type
# ---------------------------------------------------------------
# ABSTRACT SYNTAX TREE - TYPE SYSTEM
# ---------------------------------------------------------------
class
Type
(
Node
):
"""A node representing the type of another node. For instance,
the Binop node representing '5 + a', where a is an int, will have
a Type node associated with it that represents the fact that
the result of the Binop is an int.
Types can also be nested, so that for instance you can have
a type like 'pointer(pointer(int))' which represents a
double-pointer to an int.
This is an abstract base class."""
def
__init__
(
self
,
child
=
None
):
if
child
==
None
:
child
=
NullNode
()
self
.
child
=
child
def
set_base_type
(
self
,
type
):
"""Set the base (innermost) type of a type. For instance,
calling this with a pointer(int) type on a pointer() type
will give you a pointer(pointer(int))."""
if
self
.
child
.
is_null
():
self
.
child
=
type
else
:
self
.
child
.
set_base_type
(
type
)
def
get_string
(
self
):
"""Return a string corresponding to the type, e.g.
'pointer(pointer(int))'."""
raise
NotImplementedError
()
def
get_outer_string
(
self
):
"""Return only the outermost type of a type. e.g.,
calling this on a pointer(pointer(int)) type will
return 'pointer'."""
raise
NotImplementedError
()
def
is_function
(
self
):
"""Returns whether or not this type represents a
function."""
return
0
class
BaseType
(
Type
):
"""A base type representing ints, chars, etc..."""
def
__init__
(
self
,
type_str
,
child
=
None
):
Type
.
__init__
(
self
,
child
)
self
.
type_str
=
type_str
def
get_string
(
self
):
return
self
.
type_str
def
get_outer_string
(
self
):
return
self
.
type_str
class
FunctionType
(
Type
):
"""A type representing a function (for function prototypes and
function calls)."""
def
__init__
(
self
,
params
=
None
,
child
=
None
):
Type
.
__init__
(
self
,
child
)
if
(
params
==
None
):
params
=
NullNode
()
self
.
params
=
params
def
get_string
(
self
):
param_str
=
""
for
param
in
self
.
params
.
nodes
:
param_str
+=
","
+
param
.
type
.
get_string
()
return
"function(
%
s)->
%
s"
%
(
param_str
[
1
:],
self
.
child
.
get_string
())
def
get_outer_string
(
self
):
return
'function'
def
is_function
(
self
):
return
1
def
get_return_type
(
self
):
"""Returns the return type of the function. Internally,
this is stored as the nested type within the function."""
return
self
.
child
def
get_params
(
self
):
"""Returns the list of parameters for the function."""
return
self
.
params
class
PointerType
(
Type
):
"""A type representing a pointer to another (nested) type."""
def
get_string
(
self
):
return
"pointer(
%
s)"
%
self
.
child
.
get_string
()
def
get_outer_string
(
self
):
return
'pointer'
# ---------------------------------------------------------------
# PARSER GRAMMAR / AST CONSTRUCTION
#
...
...
cctlib/cttc.py
View file @
1169f44
...
...
@@ -177,7 +177,14 @@ class CodeGenVisitor (Visitor) :
def
concat
(
cls
,
outfile
,
chunks
)
:
outfile
.
write
(
"# Generated by cct
\n
"
"# Franck Pommereau (2018)
\n
"
"# Adapted from Atul Varma's c.py (Spring 2004)
\n
"
)
"# Adapted from Atul Varma's c.py (Spring 2004)
\n\n
"
)
outfile
.
write
(
"#
\n
"
"# on computer start: call main and halt
\n
"
"#
\n\n
"
"IRQ0:
\n
"
" set R9 @main
\n
"
" call R9
\n
"
" halt
\n
"
)
for
c
in
chunks
:
s
=
c
.
curr_str
.
getvalue
()
if
s
.
strip
()
:
...
...
@@ -194,13 +201,6 @@ class CodeGenVisitor (Visitor) :
outfile
.
write
(
"
\n
#
\n
# string literals from file
%
r
\n
#
\n\n
"
%
c
.
path
)
outfile
.
write
(
s
)
outfile
.
write
(
"
\n
#
\n
"
"# call main
\n
"
"#
\n\n
"
"IRQ0:
\n
"
" set R9 @main
\n
"
" call R9
\n
"
" halt
\n
"
)
def
_calc_function_var_addrs
(
self
,
symtab
,
last_fp_loc
):
self
.
_calc_function_arg_addrs
(
symtab
)
...
...
@@ -353,7 +353,7 @@ class CodeGenVisitor (Visitor) :
label_str
=
"_LC
%
d"
%
self
.
__str_literal_label
self
.
str_literal_dict
[
str
]
=
label_str
str
=
str
.
replace
(
'
\n
'
,
'
\\
12
'
)
str
=
str
.
replace
(
'
\n
'
,
'
\\
n
'
)
self
.
str_literal_str
.
write
(
"""
%
s:
\n
str "
%
s
\\
0"
\n
"""
%
(
label_str
,
str
))
self
.
__class__
.
__str_literal_label
+=
1
return
label_str
...
...
cctlib/cvisitors.py
View file @
1169f44
...
...
@@ -340,11 +340,9 @@ class SymtabVisitor(Visitor):
# TODO: might be best to just move this to the code
# generation phase, since this doesn't have anything to
# do with symbol table generation.
param_num
=
0
for
param
in
node
.
nodes
:
for
param_num
,
param
in
enumerate
(
node
.
nodes
):
param
.
accept
(
self
)
param
.
param_num
=
param_num
param_num
+=
1
def
vTranslationUnit
(
self
,
node
):
self
.
root_symtab
=
Symtab
()
...
...
cctlib/parser.py
0 → 100644
View file @
1169f44
import
pycparser
from
.
import
cast
def
_coord
(
node
)
:
if
node
.
coord
is
not
None
:
return
{
"lineno"
:
node
.
coord
.
line
,
"colno"
:
node
.
coord
.
column
-
1
,
"filename"
:
node
.
coord
.
file
}
else
:
return
{}
class
ast2ast
(
object
)
:
def
__call__
(
self
,
node
)
:
return
getattr
(
self
,
"v"
+
node
.
__class__
.
__name__
)(
node
)
# # This is the top of the AST, representing a single C file (a
# # translation unit in K&R jargon). It contains a list of
# # "external-declaration"s, which is either declarations (Decl),
# # Typedef or function definitions (FuncDef).
# #
# FileAST: [ext**]
def
vFileAST
(
self
,
node
)
:
ret
=
cast
.
TranslationUnit
(
None
,
**
_coord
(
node
))
for
_
,
child
in
node
.
children
()
:
ret
.
add
(
self
(
child
))
return
ret
# # name: the variable being declared
# # quals: list of qualifiers (const, volatile)
# # funcspec: list function specifiers (i.e. inline in C99)
# # storage: list of storage specifiers (extern, register, etc.)
# # type: declaration type (probably nested with all the modifiers)
# # init: initialization value, or None
# # bitsize: bit field size, or None
# #
# Decl: [name, quals, storage, funcspec, type*, init*, bitsize*]
def
vDecl
(
self
,
node
)
:
typ
=
self
(
node
.
type
)
ret
=
cast
.
Declaration
(
node
.
name
,
typ
,
**
_coord
(
node
))
ret
.
extern
=
"extern"
in
node
.
storage
ret
.
static
=
"static"
in
node
.
quals
return
ret
# # A typedef declaration.
# # Very similar to Decl, but without some attributes
# #
# Typedef: [name, quals, storage, type*]
def
vTypedef
(
self
,
node
)
:
raise
NotImplementedError
(
"typdef"
)
# # type <decl>(args)
# #
# FuncDecl: [args*, type*]
def
vFuncDecl
(
self
,
node
)
:
return
cast
.
FunctionType
(
self
(
node
.
args
),
self
(
node
.
type
))
# # a list of comma separated function parameter declarations
# #
# ParamList: [params**]
def
vParamList
(
self
,
node
)
:
pass
# # A base type declaration
# #
# TypeDecl: [declname, quals, type*]
def
vTypeDecl
(
self
,
node
)
:
pass
# # Function definition: a declarator for the function name and
# # a body, which is a compound statement.
# # There's an optional list of parameter declarations for old
# # K&R-style definitions
# #
# FuncDef: [decl*, param_decls**, body*]
def
vFuncDef
(
self
,
node
)
:
pass
# # ArrayDecl is a nested declaration of an array with the given type.
# # dim: the dimension (for example, constant 42)
# # dim_quals: list of dimension qualifiers, to support C99's allowing 'const'
# # and 'static' within the array dimension in function declarations.
# ArrayDecl: [type*, dim*, dim_quals]
# ArrayRef: [name*, subscript*]
# # op: =, +=, /= etc.
# #
# Assignment: [op, lvalue*, rvalue*]
# BinaryOp: [op, left*, right*]
# Break: []
# Case: [expr*, stmts**]
# Cast: [to_type*, expr*]
# # Compound statement in C99 is a list of block items (declarations or
# # statements).
# #
# Compound: [block_items**]
# # Compound literal (anonymous aggregate) for C99.
# # (type-name) {initializer_list}
# # type: the typename
# # init: InitList for the initializer list
# #
# CompoundLiteral: [type*, init*]
# # type: int, char, float, etc. see CLexer for constant token types
# #
# Constant: [type, value]
# Continue: []
# DeclList: [decls**]
# Default: [stmts**]
# DoWhile: [cond*, stmt*]
# # Represents the ellipsis (...) parameter in a function
# # declaration
# #
# EllipsisParam: []
# # An empty statement (a semicolon ';' on its own)
# #
# EmptyStatement: []
# # Enumeration type specifier
# # name: an optional ID
# # values: an EnumeratorList
# #
# Enum: [name, values*]
# # A name/value pair for enumeration values
# #
# Enumerator: [name, value*]
# # A list of enumerators
# #
# EnumeratorList: [enumerators**]
# # A list of expressions separated by the comma operator.
# #
# ExprList: [exprs**]
# # for (init; cond; next) stmt
# #
# For: [init*, cond*, next*, stmt*]
# # name: Id
# # args: ExprList
# #
# FuncCall: [name*, args*]
# Goto: [name]
# ID: [name]
# # Holder for types that are a simple identifier (e.g. the built
# # ins void, char etc. and typedef-defined types)
# #
# IdentifierType: [names]
# If: [cond*, iftrue*, iffalse*]
# # An initialization list used for compound literals.
# #
# InitList: [exprs**]
# Label: [name, stmt*]
# # A named initializer for C99.
# # The name of a NamedInitializer is a sequence of Nodes, because
# # names can be hierarchical and contain constant expressions.
# #
# NamedInitializer: [name**, expr*]
# PtrDecl: [quals, type*]
# Return: [expr*]
# # name: struct tag name
# # decls: declaration of members
# #
# Struct: [name, decls**]
# # type: . or ->
# # name.field or name->field
# #
# StructRef: [name*, type, field*]
# Switch: [cond*, stmt*]
# # cond ? iftrue : iffalse
# #
# TernaryOp: [cond*, iftrue*, iffalse*]
# Typename: [name, quals, type*]
# UnaryOp: [op, expr*]
# # name: union tag name
# # decls: declaration of members
# #
# Union: [name, decls**]
# While: [cond*, stmt*]
# Pragma: [string]
def
parse
(
path
,
*
cpp_args
)
:
ast
=
pycparser
.
parse_file
(
path
,
use_cpp
=
True
,
cpp_args
=
list
(
cpp_args
))
return
ast2ast
()(
ast
)
if
__name__
==
"__main__"
:
tree
=
parse
(
",test.c"
,
"-DTTC"
)
Please
register
or
login
to post a comment