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-20 12:36:09 +0200
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
75ec9cdd6d6c2baa933f82bcbfc3a9066605c773
75ec9cdd
1 parent
d2ca43ee
cttc.py first version, not tested yet
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
563 additions
and
5 deletions
cctlib/clex.py
cctlib/cparse.py
cctlib/cttc.py
cctlib/cvisitors.py
cctlib/cx86.py
cctlib/main.py
samples/expr.c
cctlib/clex.py
View file @
75ec9cd
# clex.py: modified by Franck Pommereau (2018)
# ---------------------------------------------------------------
# clex.py
#
...
...
cctlib/cparse.py
View file @
75ec9cd
# cparse.py: modified by Franck Pommereau (2018)
# ---------------------------------------------------------------
# cparse.py
#
...
...
@@ -755,7 +757,16 @@ def p_empty(t):
pass
def
p_error
(
t
):
print
(
"[
%
s:
%
s] syntax error"
%
(
t
.
lineno
,
t
.
lexpos
))
print
(
"[
%
s] syntax error:"
%
t
.
lineno
)
start
=
t
.
lexer
.
lexdata
.
rfind
(
"
\n
"
,
0
,
t
.
lexpos
)
if
start
==
-
1
:
start
=
0
else
:
start
+=
1
stop
=
t
.
lexer
.
lexdata
.
find
(
"
\n
"
,
t
.
lexpos
)
head
=
" "
*
len
(
"[
%
s"
%
t
.
lineno
)
print
(
" >"
+
head
+
t
.
lexer
.
lexdata
[
start
:
stop
])
print
(
" >"
+
head
+
(
" "
*
(
t
.
lexpos
-
start
))
+
"^"
)
raise
ParseError
()
yacc
.
yacc
(
debug
=
1
)
...
...
cctlib/cttc.py
0 → 100644
View file @
75ec9cd
import
io
from
.
import
cparse
from
.cvisitors
import
Visitor
##
## STACK MACHINE ABSTRACTION
##
class
TtcRegisters
(
object
):
def
__init__
(
self
,
parent
,
base_fp
):
# we keep R8 and R9 for immediate temp storage
self
.
all_regs
=
[
'R
%
s'
%
i
for
i
in
range
(
8
)]
self
.
regs_free
=
self
.
all_regs
[:]
self
.
regs_almost_free
=
[]
self
.
mem_free
=
[]
self
.
stack
=
[]
self
.
next_temp
=
base_fp
-
1
self
.
parent
=
parent
self
.
callee_save_regs_used
=
[]
self
.
caller_save_regs
=
[
'R
%
s'
%
i
for
i
in
range
(
4
)]
self
.
callee_save_regs
=
[
'R
%
s'
%
i
for
i
in
range
(
4
,
8
)]
def
o
(
self
,
str
,
comment
=
None
):
self
.
parent
.
o
(
str
,
comment
)
def
save_caller_saves
(
self
):
for
reg
in
self
.
caller_save_regs
:
if
reg
not
in
self
.
regs_free
:
self
.
_copy_reg_to_temp
([
reg
],
"Save caller-save register to temp"
)
self
.
regs_free
.
append
(
reg
)
def
save_callee_saves
(
self
):
for
reg
in
self
.
callee_save_regs_used
:
self
.
o
(
" push
%
s"
%
reg
,
"Save callee-save register"
)
def
load_callee_saves
(
self
):
for
reg
in
reversed
(
self
.
callee_save_regs_used
):
self
.
o
(
" pop
%
s"
%
reg
,
"Restore callee-save register"
)
def
_copy_reg_to_temp
(
self
,
valid_regs
,
comment_str
=
None
):
if
len
(
self
.
mem_free
)
==
0
:
self
.
mem_free
.
append
(
self
.
next_temp
)
self
.
next_temp
-=
1
mem
=
self
.
mem_free
.
pop
()
reg
=
None
index
=
0
for
i
in
self
.
stack
:
if
i
in
valid_regs
:
reg
=
i
break
index
+=
1
if
reg
==
None
:
raise
Exception
(
"No free registers inside OR outside of stack!"
)
if
comment_str
==
None
:
comment_str
=
"Stack machine: copy register to temp"
self
.
o
(
" sti
%
s
%
s"
%
(
reg
,
mem
),
comment_str
)
self
.
stack
[
index
]
=
mem
return
reg
def
_get_free_reg
(
self
,
valid_regs
,
preferred_reg
=
None
):
if
len
(
self
.
regs_free
)
>
0
:
reg
=
None
if
preferred_reg
!=
None
and
preferred_reg
in
self
.
regs_free
:
reg
=
preferred_reg
else
:
for
r
in
self
.
regs_free
:
if
r
in
valid_regs
:
reg
=
r
if
reg
!=
None
:
self
.
regs_free
.
remove
(
reg
)
if
reg
in
self
.
callee_save_regs
and
reg
not
in
self
.
callee_save_regs_used
:
self
.
callee_save_regs_used
.
append
(
reg
)
return
reg
return
self
.
_copy_reg_to_temp
(
valid_regs
)
def
push
(
self
,
preferred_reg
=
None
,
valid_regs
=
None
):
if
valid_regs
==
None
:
valid_regs
=
self
.
all_regs
reg
=
self
.
_get_free_reg
(
valid_regs
,
preferred_reg
)
self
.
stack
.
append
(
reg
)
return
reg
def
pop
(
self
,
valid_regs
=
None
):
if
valid_regs
==
None
:
valid_regs
=
self
.
all_regs
return
self
.
_pop
(
valid_regs
)
def
_pop
(
self
,
valid_regs
):
loc
=
self
.
stack
.
pop
()
if
loc
in
valid_regs
:
self
.
regs_almost_free
.
append
(
loc
)
return
loc
reg
=
self
.
_get_free_reg
(
valid_regs
)
self
.
o
(
" ldi
%
s
%
s"
%
(
reg
,
loc
),
"Stack machine: copy temp to register"
)
if
loc
in
self
.
all_regs
:
self
.
regs_free
.
append
(
loc
)
self
.
regs_almost_free
.
append
(
reg
)
return
reg
def
peek
(
self
):
return
self
.
stack
[
-
1
]
def
is_empty
(
self
):
return
len
(
self
.
stack
)
==
0
def
done
(
self
):
self
.
regs_free
.
extend
(
self
.
regs_almost_free
)
self
.
regs_almost_free
=
[]
def
get_max_fp
(
self
):
return
self
.
next_temp
+
1
##
## CODE GENERATOR
##
class
CodeGenVisitor
(
Visitor
)
:
__label
=
0
__str_literal_label
=
0
def
__init__
(
self
,
path
):
Visitor
.
__init__
(
self
)
self
.
path
=
path
self
.
str_literal_str
=
io
.
StringIO
()
self
.
str_literal_dict
=
{}
def
new_label
(
self
):
label
=
"_L
%
d"
%
self
.
__label
self
.
__class__
.
__label
+=
1
return
label
def
o
(
self
,
str
,
comment
=
None
):
if
comment
is
not
None
:
comment
=
"#
%
s"
%
comment
self
.
curr_str
.
write
(
"
%-35
s
%
s
\n
"
%
(
str
,
comment
))
elif
str
:
self
.
curr_str
.
write
(
str
+
"
\n
"
)
def
c
(
self
,
str
,
indent_amt
=
2
):
self
.
curr_str
.
write
(
"
\n
#
%
s
\n\n
"
%
str
)
def
vNodeList
(
self
,
node
):
self
.
_visitList
(
node
.
nodes
)
def
_empty_stack
(
self
,
node
):
if
not
self
.
stack
.
is_empty
():
self
.
stack
.
pop
()
self
.
stack
.
done
()
if
not
self
.
stack
.
is_empty
():
raise
Exception
(
"PANIC! Register stack isn't empty!"
)
def
_accept_and_empty_stack
(
self
,
node
):
node
.
accept
(
self
)
self
.
_empty_stack
(
node
)
def
vStatementList
(
self
,
node
):
for
n
in
node
.
nodes
:
self
.
_accept_and_empty_stack
(
n
)
def
_generate_global_variable_definitions
(
self
,
node
):
globals_str
=
io
.
StringIO
()
for
symbol
in
node
.
symtab
.
entries
.
values
():
symbol
.
compile_loc
=
symbol
.
name
if
not
symbol
.
type
.
is_function
()
and
not
symbol
.
extern
:
globals_str
.
write
(
"
%
s:
\n
int 0
\n
"
%
symbol
.
compile_loc
)
return
globals_str
def
vTranslationUnit
(
self
,
node
):
self
.
curr_str
=
io
.
StringIO
()
self
.
globals_str
=
self
.
_generate_global_variable_definitions
(
node
)
self
.
_visitList
(
node
.
nodes
)
@classmethod
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
"
)
for
c
in
chunks
:
outfile
.
write
(
"
\n
# code from file
%
r
\n
"
%
c
.
path
)
outfile
.
write
(
c
.
curr_str
.
getvalue
())
for
c
in
chunks
:
outfile
.
write
(
"
\n
# globals from file
%
r
\n\n
"
%
c
.
path
)
outfile
.
write
(
c
.
globals_str
.
getvalue
())
for
c
in
chunks
:
outfile
.
write
(
"
\n
# string literals from file
%
r
\n\n
"
%
c
.
path
)
outfile
.
write
(
c
.
str_literal_str
.
getvalue
())
def
_calc_function_var_addrs
(
self
,
symtab
,
last_fp_loc
):
self
.
_calc_function_arg_addrs
(
symtab
)
return
self
.
_calc_local_var_addrs
(
symtab
.
children
[
0
],
last_fp_loc
)
def
_calc_function_arg_addrs
(
self
,
symtab
):
for
symbol
in
symtab
.
entries
.
values
():
symbol
.
compile_loc
=
2
+
symbol
.
param_num
if
not
symbol
.
is_used
:
self
.
warning
(
"function argument '
%
s' is never used."
%
symbol
.
name
)
def
_calc_local_var_addrs
(
self
,
symtab
,
last_fp_loc
):
for
symbol
in
symtab
.
entries
.
values
():
if
symbol
.
extern
:
symbol
.
compile_loc
=
"@"
+
symbol
.
name
continue
last_fp_loc
-=
1
symbol
.
compile_loc
=
last_fp_loc
if
not
symbol
.
is_used
:
self
.
warning
(
"local variable '
%
s' is never used."
%
symbol
.
name
)
max_last_fp
=
last_fp_loc
for
kid
in
symtab
.
children
:
curr_last_fp
=
self
.
_calc_local_var_addrs
(
kid
,
last_fp_loc
)
if
curr_last_fp
<
max_last_fp
:
max_last_fp
=
curr_last_fp
return
max_last_fp
def
_fill_line
(
self
,
str
,
width
=
70
):
extra
=
"-"
*
(
width
-
1
-
len
(
str
))
return
str
+
" "
+
extra
def
vFunctionDefn
(
self
,
node
):
self
.
break_labels
=
[]
self
.
continue_labels
=
[]
self
.
curr_func_end_label
=
self
.
new_label
()
+
"_function_end"
stack_frame_size
=
self
.
_calc_function_var_addrs
(
node
.
symtab
,
0
)
line
=
self
.
_fill_line
(
"BEGIN FUNCTION:
%
s()"
%
node
.
name
)
self
.
c
(
"
%
s
\n
#
\n
# Function type:
%
s"
%
(
line
,
node
.
type
.
get_string
()),
0
)
self
.
o
(
"
%
s:"
%
node
.
compile_loc
)
self
.
o
(
" push BP"
,
"Save old frame pointer"
)
self
.
o
(
" mov SP BP"
,
"Set new frame pointer"
)
self
.
stack
=
TtcRegisters
(
self
,
stack_frame_size
)
old_str
=
self
.
curr_str
self
.
curr_str
=
io
.
StringIO
()
node
.
body
.
accept
(
self
)
function_str
=
self
.
curr_str
self
.
curr_str
=
old_str
frame_size
=
self
.
stack
.
get_max_fp
()
if
frame_size
>
0
:
self
.
o
(
" set R9
%
X"
%
frame_size
,
"Allocate
%
s words for local+temp vars"
%
frame_size
)
self
.
o
(
" sub R9 SP SP"
,
"... shift SP"
)
self
.
stack
.
save_callee_saves
()
self
.
curr_str
.
write
(
function_str
.
getvalue
())
self
.
o
(
"
%
s:"
%
self
.
curr_func_end_label
)
self
.
stack
.
load_callee_saves
()
self
.
o
(
" mov BP SP"
,
"Deallocate local+temp vars"
)
self
.
o
(
" pop BP"
,
"Restore old stack frame"
)
self
.
o
(
" ret"
)
line
=
self
.
_fill_line
(
"END FUNCTION:
%
s()"
%
node
.
name
)
self
.
c
(
line
,
0
)
def
vCompoundStatement
(
self
,
node
):
node
.
statement_list
.
accept
(
self
)
def
vIfStatement
(
self
,
node
):
done_label
=
self
.
new_label
()
+
"_done"
if
not
node
.
else_stmt
.
is_null
():
else_label
=
self
.
new_label
()
+
"_else"
else
:
else_label
=
done_label
self
.
c
(
"IF statment - begin"
)
node
.
expr
.
accept
(
self
)
comparer
=
self
.
stack
.
pop
()
self
.
stack
.
done
()
self
.
o
(
" set R9 @
%
s"
%
else_label
,
"Point towards else clause"
)
self
.
o
(
" jz
%
s R9"
%
comparer
,
"... if result is zero, jump to it"
)
self
.
c
(
"IF statment - THEN clause - begin"
)
self
.
_accept_and_empty_stack
(
node
.
then_stmt
)
self
.
c
(
"IF statment - THEN clause - end"
)
self
.
o
(
" set R9 @
%
s"
%
done_label
,
"Point towards if end"
)
self
.
o
(
" jmp R9"
,
"... jump to it"
)
self
.
c
(
"IF statment - ELSE clause - begin"
)
self
.
o
(
"
%
s:"
%
else_label
)
if
not
node
.
else_stmt
.
is_null
():
self
.
_accept_and_empty_stack
(
node
.
else_stmt
)
self
.
c
(
"IF statment - ELSE clause - end"
)
self
.
o
(
"
%
s:"
%
done_label
)
self
.
c
(
"IF statment - end"
)
def
_push_loop_labels
(
self
,
break_label
,
continue_label
):
self
.
break_labels
.
append
(
break_label
)
self
.
continue_labels
.
append
(
continue_label
)
def
_pop_loop_labels
(
self
):
self
.
break_labels
.
pop
()
self
.
continue_labels
.
pop
()
def
vWhileLoop
(
self
,
node
):
test_label
=
self
.
new_label
()
+
"_test"
done_label
=
self
.
new_label
()
+
"_done"
self
.
_push_loop_labels
(
break_label
=
done_label
,
continue_label
=
test_label
)
self
.
c
(
"WHILE loop - begin"
)
self
.
o
(
"
%
s:"
%
test_label
)
node
.
expr
.
accept
(
self
)
comparer
=
self
.
stack
.
pop
()
self
.
stack
.
done
()
self
.
o
(
" set R9 @
%
s"
%
done_label
,
"Point towards loop exit"
)
self
.
o
(
" jz
%
s R9"
%
comparer
,
"... if result is zero, jump to it"
)
self
.
_accept_and_empty_stack
(
node
.
stmt
)
self
.
o
(
" set R9 @
%
s"
%
test_label
,
"Point towards loop start"
)
self
.
o
(
" jmp R9"
,
"... jump to it"
)
self
.
o
(
"
%
s:"
%
done_label
)
self
.
c
(
"WHILE loop - end"
)
self
.
_pop_loop_labels
()
def
vForLoop
(
self
,
node
):
test_label
=
self
.
new_label
()
+
"_test"
done_label
=
self
.
new_label
()
+
"_done"
self
.
_push_loop_labels
(
break_label
=
done_label
,
continue_label
=
test_label
)
self
.
c
(
"FOR loop - begin"
)
self
.
_accept_and_empty_stack
(
node
.
begin_stmt
)
self
.
o
(
"
%
s:"
%
test_label
)
node
.
expr
.
accept
(
self
)
comparer
=
self
.
stack
.
pop
()
self
.
stack
.
done
()
self
.
o
(
" set R9 @
%
s"
%
done_label
,
"Point towards loop exit"
)
self
.
o
(
" jz
%
s R9"
%
comparer
,
"... if result is zero, jump to it"
)
self
.
_accept_and_empty_stack
(
node
.
stmt
)
self
.
_accept_and_empty_stack
(
node
.
end_stmt
)
self
.
o
(
" set R9 @
%
s"
%
test_label
,
"Point towards while loop start"
)
self
.
o
(
" jmp R9"
,
"... jump to it"
)
self
.
o
(
"
%
s:"
%
done_label
)
self
.
c
(
"FOR loop - end"
)
self
.
_pop_loop_labels
()
def
vBreakStatement
(
self
,
node
):
self
.
o
(
" set R9 @
%
s"
%
self
.
break_labels
[
-
1
],
"Loop: break statement"
)
self
.
o
(
" jmp R9"
,
"... jump to loop exit"
)
def
vContinueStatement
(
self
,
node
):
self
.
o
(
" set R9 @
%
s"
%
self
.
continue_labels
[
-
1
],
"Loop: continue statement"
)
self
.
o
(
" jmp R9"
,
"... jump to loop start"
)
def
_get_new_str_literal_label
(
self
,
str
):
if
str
in
self
.
str_literal_dict
:
return
self
.
str_literal_dict
[
str
]
label_str
=
"_LC
%
d"
%
self
.
__str_literal_label
self
.
str_literal_dict
[
str
]
=
label_str
str
=
str
.
replace
(
'
\n
'
,
'
\\
12'
)
self
.
str_literal_str
.
write
(
"""
%
s:
\n
str "
%
s
\\
0"
\n
"""
%
(
label_str
,
str
))
self
.
__class__
.
__str_literal_label
+=
1
return
label_str
def
vStringLiteral
(
self
,
node
):
label_str
=
self
.
_get_new_str_literal_label
(
node
.
get_str
())
COMMENT_CHARS
=
7
comment_label
=
node
.
get_sanitized_str
()
if
len
(
comment_label
)
>
COMMENT_CHARS
:
comment_label
=
"
%
s..."
%
comment_label
[
0
:
COMMENT_CHARS
]
self
.
o
(
" set
%
s @
%
s"
%
(
self
.
stack
.
push
(),
label_str
),
"Get addr of string literal '
%
s'"
%
comment_label
)
def
vConst
(
self
,
node
):
self
.
o
(
" set
%
s
%
X"
%
(
self
.
stack
.
push
(),
node
.
value
),
"Load numeric constant
%
d"
%
node
.
value
)
def
vId
(
self
,
node
):
if
node
.
output_addr
:
if
isinstance
(
node
.
symbol
.
compile_loc
,
int
)
:
self
.
o
(
" set R9
%
X"
%
node
.
symbol
.
compile_loc
,
"Get BP-relative address of
%
s"
%
node
.
symbol
.
name
)
self
.
o
(
" add R9 BP
%
s"
%
self
.
stack
.
push
(),
"Compute address of
%
s"
%
node
.
symbol
.
name
)
else
:
self
.
o
(
" set
%
s @
%
s"
%
(
self
.
stack
.
push
(),
node
.
symbol
.
compile_loc
),
"Get address of
%
s"
%
node
.
symbol
.
name
)
return
reg
=
self
.
stack
.
push
()
if
isinstance
(
node
.
symbol
.
compile_loc
,
int
)
:
self
.
o
(
" ldi
%
s
%
s"
%
(
reg
,
node
.
symbol
.
compile_loc
),
"Get value of
%
s"
%
node
.
symbol
.
name
)
else
:
self
.
o
(
" set
%
s @
%
s"
%
(
reg
,
node
.
symbol
.
compile_loc
),
"Get address of
%
s"
%
node
.
symbol
.
name
)
self
.
o
(
" ld
%
s
%
s"
%
(
reg
,
reg
),
"Get value of
%
s"
%
node
.
symbol
.
name
)
def
vArrayExpression
(
self
,
node
):
node
.
expr
.
accept
(
self
)
node
.
index
.
accept
(
self
)
reg_index
=
self
.
stack
.
pop
()
reg_expr
=
self
.
stack
.
pop
()
reg_to
=
self
.
stack
.
push
()
self
.
stack
.
done
()
self
.
o
(
" add
%
s
%
s
%
s"
%
(
reg_expr
,
reg_index
,
reg_to
),
"Load addr of array index"
)
if
not
node
.
output_addr
:
self
.
o
(
" ld
%
s
%
s"
%
(
reg_to
,
reg_to
),
"Load array value"
)
def
vFunctionExpression
(
self
,
node
):
self
.
c
(
"FUNCTION CALL to
%
s() - begin"
%
node
.
function
.
symbol
.
name
)
self
.
stack
.
save_caller_saves
()
argnum
=
len
(
node
.
arglist
.
nodes
)
for
arg
in
reversed
(
node
.
arglist
.
nodes
):
arg_reg
=
self
.
_accept_and_pop
(
arg
)
self
.
o
(
" push
%
s"
%
arg_reg
,
"Push arg
%
d"
%
argnum
)
self
.
stack
.
done
()
argnum
-=
1
self
.
o
(
" set R9 @
%
s"
%
node
.
function
.
symbol
.
compile_loc
,
"Point towards function
%
s()"
%
node
.
function
.
symbol
.
compile_loc
)
self
.
o
(
" call R9"
,
"... call it"
)
result
=
self
.
stack
.
push
(
preferred_reg
=
'R0'
)
if
result
!=
'R0'
:
self
.
o
(
" mov R0
%
s"
%
result
,
"Copy return value"
)
arg_stack_size
=
len
(
node
.
arglist
.
nodes
)
if
arg_stack_size
>
0
:
self
.
o
(
" set R9
%
X"
%
arg_stack_size
,
"Deallocate argument stack"
)
self
.
o
(
" add R9 SP SP"
,
"... shift SP"
)
self
.
c
(
"FUNCTION CALL to
%
s() - end"
%
node
.
function
.
symbol
.
name
)
def
vReturnStatement
(
self
,
node
):
return_reg
=
self
.
_accept_and_pop
(
node
.
expr
)
self
.
o
(
" mov
%
s R0"
%
return_reg
,
"Set return value"
)
self
.
o
(
" set R9 @
%
s"
%
self
.
curr_func_end_label
,
"Point towards function exit"
)
self
.
o
(
" jmp R9"
,
"... jump to it"
)
self
.
stack
.
done
()
def
_accept_and_pop
(
self
,
node
):
if
node
.
is_const
():
self
.
o
(
" set R8
%
X"
%
node
.
value
,
"Use constant
%
s"
%
node
.
value
)
return
"R8"
else
:
node
.
accept
(
self
)
return
self
.
stack
.
pop
()
def
_binop_assign
(
self
,
node
):
node
.
left
.
accept
(
self
)
right_reg
=
self
.
_accept_and_pop
(
node
.
right
)
left_reg
=
self
.
stack
.
pop
()
reg
=
self
.
stack
.
push
()
if
node
.
op
==
"="
:
self
.
o
(
" mov
%
s
%
s"
%
(
right_reg
,
reg
),
"Assignement '=': set result"
)
elif
node
.
op
==
"+="
:
self
.
o
(
" ld
%
s
%
s"
%
(
left_reg
,
reg
),
"Assignement '+=': load initial left value"
)
self
.
o
(
" add
%
s
%
s
%
s"
%
(
reg
,
right_reg
,
reg
),
"... add right value"
)
elif
node
.
op
==
"-="
:
self
.
o
(
" ld
%
s
%
s"
%
(
left_reg
,
reg
),
"Assignement '-=': load initial left value"
)
self
.
o
(
" sub
%
s
%
s
%
s"
%
(
reg
,
right_reg
,
reg
),
"... subtract right value"
)
else
:
raise
Exception
(
"unsupported assignment
%
r"
%
node
.
op
)
self
.
o
(
" st
%
s
%
s"
%
(
reg
,
left_reg
),
"... save value"
)
self
.
stack
.
done
()
_binary_operations
=
{
"+"
:
"add"
,
"-"
:
"sub"
,
"*"
:
"mul"
,
"/"
:
"div"
,
"
%
"
:
"mod"
,
"<<"
:
"lshift"
,
">>"
:
"rshift"
,
"&&"
:
"and"
,
"||"
:
"or"
,
"&"
:
"and"
,
"|"
:
"or"
,
"^"
:
"xor"
}
def
_binop_arith
(
self
,
node
):
node
.
left
.
accept
(
self
)
right_reg
=
self
.
_accept_and_pop
(
node
.
right
)
left_reg
=
self
.
stack
.
pop
()
try
:
instr
=
self
.
_binary_operations
[
node
.
op
]
except
KeyError
:
raise
Exception
(
"unsupported operation
%
r"
%
node
.
op
)
self
.
o
(
"
%
s
%
s
%
s
%
s"
%
(
instr
.
ljust
(
4
),
left_reg
,
right_reg
,
left_reg
),
"Perform '
%
s'"
%
node
.
op
)
self
.
stack
.
done
()
new_reg
=
self
.
stack
.
push
(
preferred_reg
=
left_reg
)
if
new_reg
!=
left_reg
:
raise
Exception
(
"PANIC! Binop push() isn't same as last pop()!"
)
def
_binop_compare
(
self
,
node
):
node
.
left
.
accept
(
self
)
right_reg
=
self
.
_accept_and_pop
(
node
.
right
)
left_reg
=
self
.
stack
.
pop
()
self
.
stack
.
done
()
reg
=
self
.
stack
.
push
()
if
node
.
op
==
"=="
:
self
.
o
(
" eq
%
s
%
s
%
s"
%
(
left_reg
,
right_reg
,
reg
),
"Perform '=='"
)
elif
node
.
op
==
"!="
:
self
.
o
(
" eq
%
s
%
s
%
s"
%
(
left_reg
,
right_reg
,
reg
),
"Perform '!='"
)
self
.
o
(
" not
%
s
%
s"
%
(
reg
,
reg
),
"... throught 'not =='"
)
elif
node
.
op
==
">"
:
self
.
o
(
" gt
%
s
%
s
%
s"
%
(
left_reg
,
right_reg
,
reg
),
"Perform '>'"
)
elif
node
.
op
==
"<"
:
self
.
o
(
" gt
%
s
%
s
%
s"
%
(
right_reg
,
left_reg
,
reg
),
"Perform '<'"
)
elif
node
.
op
==
">="
:
self
.
o
(
" gt
%
s
%
s
%
s"
%
(
right_reg
,
left_reg
,
reg
),
"Perform '>='"
)
self
.
o
(
" not
%
s
%
s"
%
(
reg
,
reg
),
"... throught 'not <'"
)
elif
node
.
op
==
"<="
:
self
.
o
(
" gt
%
s
%
s
%
s"
%
(
left_reg
,
right_reg
,
reg
),
"Perform '<='"
)
self
.
o
(
" not
%
s
%
s"
%
(
reg
,
reg
),
"... throught 'not >'"
)
else
:
raise
Exception
(
"unsupported comparison
%
r"
%
node
.
op
)
def
vBinop
(
self
,
node
):
if
node
.
op
in
cparse
.
Binop
.
ASSIGN_OPS
:
self
.
_binop_assign
(
node
)
elif
node
.
op
in
[
'+'
,
'-'
,
'*'
]:
self
.
_binop_arith
(
node
)
elif
node
.
op
in
[
'=='
,
'!='
,
'<'
,
'>'
,
'<='
,
'>='
]:
self
.
_binop_compare
(
node
)
def
vNegative
(
self
,
node
):
node
.
expr
.
accept
(
self
)
reg
=
self
.
stack
.
peek
()
self
.
o
(
" neg
%
s
%
s"
%
(
reg
,
reg
),
"Perform unary negation"
)
def
vPointer
(
self
,
node
):
node
.
expr
.
accept
(
self
)
if
node
.
output_addr
:
self
.
o
(
""
,
"(Getting pointer target addr via '*')"
)
return
reg_from
=
self
.
stack
.
pop
()
reg_to
=
self
.
stack
.
push
()
self
.
o
(
" ld
%
s
%
s"
%
(
reg_from
,
reg_to
),
"Pointer dereference"
)
self
.
stack
.
done
()
def
vAddrOf
(
self
,
node
):
node
.
expr
.
accept
(
self
)
self
.
o
(
""
,
"(Address-of operator '&' used here)"
)
cctlib/cvisitors.py
View file @
75ec9cd
# cvisitors.py: modified by Franck Pommereau (2018)
# ---------------------------------------------------------------
# cvisitors.py
#
...
...
cctlib/cx86.py
View file @
75ec9cd
# cx86.py: modified by Franck Pommereau (2018)
# ---------------------------------------------------------------
# cx86.py
#
...
...
@@ -177,7 +179,7 @@ class x86Registers:
"""Emits code that pops the callee-save registers used by
the stack machine off the process' stack."""
for
reg
in
self
.
callee_save_regs_used
:
for
reg
in
reversed
(
self
.
callee_save_regs_used
)
:
self
.
o
(
" popl
%
s"
%
reg
,
"Restore callee-save register"
)
...
...
cctlib/main.py
View file @
75ec9cd
import
argparse
,
sys
,
os.path
import
ply.yacc
as
yacc
from
.
import
cparse
,
cvisitors
,
cx86
cttc
=
cx86
from
.
import
cparse
,
cvisitors
,
cx86
,
cttc
ARCH
=
{
"x86"
:
cx86
,
"ttc"
:
cttc
}
...
...
@@ -95,7 +94,7 @@ def main (args=None) :
ast_file
=
open
(
ast_path
,
"w"
)
else
:
ast_file
=
None
code
=
"
\n
"
.
join
(
open
(
src
)
.
readlines
())
code
=
"
\n
"
.
join
(
l
.
rstrip
()
for
l
in
open
(
src
)
.
readlines
())
ret
=
Compiler
(
ARCH
[
args
.
arch
],
src
)
.
compile
(
code
,
ast_file
)
if
ast_file
is
not
None
:
ast_file
.
close
()
...
...
samples/expr.c
0 → 100644
View file @
75ec9cd
int
main
(
int
argc
,
char
**
argv
)
{
int
a
;
int
b
;
int
c
;
int
d
;
a
=
1
;
b
=
1
+
a
;
c
=
1
+
a
+
b
;
d
=
1
+
a
+
b
+
c
;
a
=
a
*
(
1
*
a
+
2
*
b
+
3
*
c
+
4
*
d
)
-
b
*
(
2
*
a
+
3
*
b
+
4
*
c
+
4
*
d
);
}
Please
register
or
login
to post a comment