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-19 11:20:43 +0200
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
d2ca43eebe2b99b77cf383c275994aedb859d47e
d2ca43ee
1 parent
35947cbb
generate a single output file
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
77 additions
and
65 deletions
cctlib/cx86.py
cctlib/main.py
samples/foo.c
samples/foo_lib.c
cctlib/cx86.py
View file @
d2ca43e
...
...
@@ -6,6 +6,8 @@
# $Id: cx86.py,v 1.3 2004/06/02 21:05:23 varmaa Exp $
# ---------------------------------------------------------------
import
io
from
.
import
cparse
from
.cvisitors
import
Visitor
...
...
@@ -394,28 +396,25 @@ class CodeGenVisitor(Visitor):
"""Visitor that generates x86 assembly code for the abstract
syntax tree."""
def
__init__
(
self
,
file
,
show_comments
=
0
):
# The current label number we're on, for generating
# jump labels in the assembly code (e.g., 'LO', 'L1', etc).
__label
=
0
# Current label number for generating string literal labels.
__str_literal_label
=
0
def
__init__
(
self
,
path
):
"""Constructor. 'file' is the file object to output the
resulting code to. If 'show_comments' is true, then annotated
comments are produced for the generated assembly code."""
resulting code to."""
Visitor
.
__init__
(
self
)
# The current label number we're on, for generating
# jump labels in the assembly code (e.g., 'LO', 'L1', etc).
self
.
__label
=
0
# Current label number for generating string literal labels.
self
.
__str_literal_label
=
0
# path of compiled C source
self
.
path
=
path
# Current assembly code for string literals.
self
.
__str_literal_str
=
""
# Whether we should show comments or not.
self
.
show_comments
=
show_comments
# The file we're outputting the generated code to.
self
.
file
=
file
self
.
str_literal_str
=
io
.
StringIO
()
self
.
str_literal_dict
=
{}
# A hashtable of binary operators and the assembly
# instructions corresponding to them. Certain instructions
...
...
@@ -454,7 +453,7 @@ class CodeGenVisitor(Visitor):
"""Generate a new jump label and return it."""
label
=
".L
%
d"
%
self
.
__label
self
.
__label
+=
1
self
.
__
class__
.
__
label
+=
1
return
label
def
o
(
self
,
str
,
comment
=
None
):
...
...
@@ -462,22 +461,20 @@ class CodeGenVisitor(Visitor):
with an optional annotated comment (if comments are
enabled)."""
if
self
.
show_comments
and
comment
!=
None
:
if
comment
!=
None
:
comment
=
"#
%
s"
%
comment
self
.
curr_str
+=
"
%-35
s
%
s
\n
"
%
(
str
,
comment
)
self
.
curr_str
.
write
(
"
%-35
s
%
s
\n
"
%
(
str
,
comment
)
)
else
:
if
str
==
""
:
return
self
.
curr_str
+=
str
+
"
\n
"
self
.
curr_str
.
write
(
str
+
"
\n
"
)
def
c
(
self
,
str
,
indent_amt
=
2
):
"""Output a single-line comment to the output file, if
comments are enabled."""
"Output a single-line comment to the output file."
indent
=
" "
*
indent_amt
if
self
.
show_comments
:
self
.
o
(
"
\n
%
s#
%
s
\n
"
%
(
indent
,
str
))
self
.
o
(
"
\n
%
s#
%
s
\n
"
%
(
indent
,
str
))
def
vNodeList
(
self
,
node
):
self
.
_visitList
(
node
.
nodes
)
...
...
@@ -513,36 +510,43 @@ class CodeGenVisitor(Visitor):
"""Generate and return a list of global variable
definitions."""
globals_str
=
".global_vars:
\n
"
globals_str
=
io
.
StringIO
()
for
symbol
in
node
.
symtab
.
entries
.
values
():
symbol
.
compile_loc
=
self
.
symbol_prepend
+
symbol
.
name
if
not
symbol
.
type
.
is_function
()
and
not
symbol
.
extern
:
globals_str
+=
" .comm
%
s,
%
d
\n
"
%
\
(
symbol
.
compile_loc
,
\
self
.
_calc_var_size
(
symbol
.
type
)
*
WEIRD_MULTIPLIER
)
globals_str
.
write
(
" .comm
%
s,
%
d
\n
"
%
(
symbol
.
compile_loc
,
self
.
_calc_var_size
(
symbol
.
type
)
*
WEIRD_MULTIPLIER
)
)
return
globals_str
def
vTranslationUnit
(
self
,
node
):
"""Outputs the entire assembly source file."""
self
.
curr_str
=
""
self
.
o
(
"# Generated by c.py"
)
self
.
o
(
"# Atul Varma (Spring 2004)
\n
"
)
self
.
o
(
" .text"
)
self
.
curr_str
=
io
.
StringIO
()
globals_str
=
self
.
_generate_global_variable_definitions
(
node
)
self
.
globals_str
=
self
.
_generate_global_variable_definitions
(
node
)
# Generate the main code.
self
.
_visitList
(
node
.
nodes
)
# Append global variable definitions.
self
.
o
(
globals_str
)
# Append string literal definitions.
self
.
o
(
self
.
__str_literal_str
)
# Output the entire file.
self
.
file
.
write
(
self
.
curr_str
)
@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\n
"
)
#
outfile
.
write
(
".text
\n\n
"
)
for
c
in
chunks
:
outfile
.
write
(
"# code from file
%
r
\n
"
%
c
.
path
)
outfile
.
write
(
c
.
curr_str
.
getvalue
())
#
outfile
.
write
(
".global_vars:
\n\n
"
)
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_var_size
(
self
,
type
):
"""Calculate and return the size of the given type, in
...
...
@@ -674,7 +678,7 @@ class CodeGenVisitor(Visitor):
# insert it into our code later on.
old_str
=
self
.
curr_str
self
.
curr_str
=
""
self
.
curr_str
=
io
.
StringIO
()
node
.
body
.
accept
(
self
)
...
...
@@ -692,7 +696,7 @@ class CodeGenVisitor(Visitor):
self
.
stack
.
save_callee_saves
()
# Add the previously-generated assembly code for the function.
self
.
curr_str
+=
function_str
self
.
curr_str
.
write
(
function_str
.
getvalue
())
self
.
o
(
"
%
s:"
%
self
.
curr_func_end_label
)
...
...
@@ -816,10 +820,14 @@ class CodeGenVisitor(Visitor):
generate (but do not yet emit) the assembly for it, and return
the name of the new label."""
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
+=
"""
%
s:
\n
.ascii "
%
s
\\
0"
\n
"""
%
(
label_str
,
str
)
self
.
__str_literal_label
+=
1
self
.
str_literal_str
.
write
(
"""
%
s:
\n
.ascii "
%
s
\\
0"
\n
"""
%
(
label_str
,
str
)
)
self
.
__
class__
.
__
str_literal_label
+=
1
return
label_str
def
vStringLiteral
(
self
,
node
):
...
...
cctlib/main.py
View file @
d2ca43e
...
...
@@ -20,8 +20,9 @@ class Compiler (object) :
"""This object encapsulates the front-end for the compiler and
serves as a facade interface to the 'meat' of the compiler
underneath."""
def
__init__
(
self
,
arch
)
:
def
__init__
(
self
,
arch
,
path
)
:
self
.
arch
=
arch
self
.
path
=
path
self
.
total_errors
=
0
self
.
total_warnings
=
0
def
_parse
(
self
)
:
...
...
@@ -34,37 +35,39 @@ class Compiler (object) :
self
.
total_warnings
+=
visitor
.
warnings
if
visitor
.
has_errors
():
raise
CompileError
()
def
_do_compile
(
self
,
outfile
,
ast_file
)
:
def
_do_compile
(
self
,
ast_file
)
:
"""Compiles the code to the given file object. Enabling
show_ast prints out the abstract syntax tree."""
self
.
_parse
()
self
.
_compile_phase
(
cvisitors
.
SymtabVisitor
())
self
.
_compile_phase
(
cvisitors
.
TypeCheckVisitor
())
self
.
_compile_phase
(
cvisitors
.
FlowControlVisitor
())
self
.
_compile_phase
(
self
.
arch
.
CodeGenVisitor
(
outfile
))
comp
=
self
.
arch
.
CodeGenVisitor
(
self
.
path
)
self
.
_compile_phase
(
comp
)
if
ast_file
is
not
None
:
self
.
_compile_phase
(
cvisitors
.
ASTPrinterVisitor
(
ast_file
))
return
comp
def
_print_stats
(
self
)
:
"Prints the total number of errors/warnings from compilation."
if
self
.
total_errors
:
print
(
"
%
d errors"
%
self
.
total_errors
)
if
self
.
total_warnings
:
print
(
"
%
s warnings"
%
self
.
total_warnings
)
def
compile
(
self
,
code
,
outfile
,
show_ast
)
:
def
compile
(
self
,
code
,
show_ast
)
:
"Compiles the given code string to the given file object."
self
.
code
=
code
try
:
self
.
_do_compile
(
outfile
,
show_ast
)
chunk
=
self
.
_do_compile
(
show_ast
)
except
cparse
.
ParseError
:
print
(
"Errors encountered, bailing."
)
return
1
return
except
CompileError
:
self
.
_print_stats
()
print
(
"Errors encountered, bailing."
)
return
1
return
self
.
_print_stats
()
print
(
"Compile successful."
)
return
0
return
chunk
def
main
(
args
=
None
)
:
parser
=
argparse
.
ArgumentParser
(
prog
=
"cct"
,
...
...
@@ -83,6 +86,7 @@ def main (args=None) :
parser
.
add_argument
(
"source"
,
nargs
=
"+"
,
metavar
=
"PATH"
,
help
=
"C source files(s) to compile"
)
args
=
parser
.
parse_args
(
args
)
chunks
=
[]
for
src
in
args
.
source
:
print
(
"Compiling
%
r"
%
src
)
if
args
.
ast
:
...
...
@@ -92,8 +96,10 @@ def main (args=None) :
else
:
ast_file
=
None
code
=
"
\n
"
.
join
(
open
(
src
)
.
readlines
())
ret
val
=
Compiler
(
ARCH
[
args
.
arch
])
.
compile
(
code
,
args
.
o
,
ast_file
)
ret
=
Compiler
(
ARCH
[
args
.
arch
],
src
)
.
compile
(
code
,
ast_file
)
if
ast_file
is
not
None
:
ast_file
.
close
()
if
retval
!=
0
:
sys
.
exit
(
retval
)
if
ret
is
None
:
sys
.
exit
(
1
)
chunks
.
append
(
ret
)
ARCH
[
args
.
arch
]
.
CodeGenVisitor
.
concat
(
args
.
o
,
chunks
)
...
...
samples/foo.c
View file @
d2ca43e
...
...
@@ -149,5 +149,11 @@ int main(int argc, char **argv) {
printf
(
"array-built string is: %s
\n
"
,
c
);
free
(
c
);
}
/* multiple defined strings */
printf
(
"this string is defined twice
\n
"
);
printf
(
"this string is defined twice
\n
"
);
return
0
;
}
...
...
samples/foo_lib.c
View file @
d2ca43e
...
...
@@ -11,16 +11,8 @@
/* Test global variable. */
int
stuff_count
;
/* Test of static function definition, to make sure it
doesn't conflict with fib() defined in foo.c. */
static
int
fib
()
{
return
stuff_count
+=
1
;
}
/* Increment global variable. */
int
increment_stuff_count
()
{
fib
();
return
0
;
return
stuff_count
+=
1
;
}
...
...
Please
register
or
login
to post a comment