Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
latte
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
zygzagZ
latte
Commits
f63ff4e9
Commit
f63ff4e9
authored
Jan 05, 2021
by
zygzagZ
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor Compiler - oddzielony generator kodu czwórkowego
parent
5b9b463e
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
746 additions
and
665 deletions
+746
-665
Makefile
Makefile
+6
-3
Compiler.cpp
src/Compiler.cpp
+8
-529
Compiler.h
src/Compiler.h
+11
-133
QuadrupleGenerator.cpp
src/codeGen/QuadrupleGenerator.cpp
+531
-0
QuadrupleGenerator.h
src/codeGen/QuadrupleGenerator.h
+190
-0
No files found.
Makefile
View file @
f63ff4e9
CC
=
g++
CCFLAGS
=
-g
-W
-Wall
-O0
-std
=
c++2a
-Wno-unused-parameter
OBJS
=
Absyn.o Lexer.o Parser.o Printer.o TypeCheck.o Info.o Skeleton.o ParseError.o Compiler.o Quadruple.o BasicBlock.o
OBJS
=
Absyn.o Lexer.o Parser.o Printer.o TypeCheck.o Info.o Skeleton.o ParseError.o Compiler.o Quadruple.o BasicBlock.o
QuadrupleGenerator.o
.PHONY
:
clean distclean
...
...
@@ -32,7 +32,7 @@ Skeleton.o : src/Skeleton.cpp src/Skeleton.h src/Absyn.h
TypeCheck.o
:
src/TypeCheck.cpp src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h
${
CC
}
${
CCFLAGS
}
-c
src/TypeCheck.cpp
Compiler.o
:
src/Compiler.cpp src/Compiler.h src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h src/codeGen/Quadruple.h src/codeGen/Variable.h
Compiler.o
:
src/Compiler.cpp src/Compiler.h src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h src/codeGen/Quadruple.h src/codeGen/Variable.h
src/codeGen/QuadrupleGenerator.h
${
CC
}
${
CCFLAGS
}
-c
src/Compiler.cpp
Info.o
:
src/Info.cpp src/Info.h src/InfoList.h src/Absyn.h
...
...
@@ -50,7 +50,10 @@ Variable.o : src/codeGen/Quadruple.h src/codeGen/Variable.cpp src/Info.h src/Inf
BasicBlock.o
:
src/codeGen/Quadruple.h src/codeGen/BasicBlock.h src/codeGen/BasicBlock.cpp src/codeGen/Variable.h src/Info.h src/InfoList.h src/Absyn.h
${
CC
}
${
CCFLAGS
}
-c
src/codeGen/BasicBlock.cpp
Latte.o
:
src/Latte.cpp src/Parser.h src/Printer.h src/Absyn.h src/ParseError.h src/TypeCheck.h src/Compiler.h src/Info.h src/InfoList.h
QuadrupleGenerator.o
:
src/codeGen/QuadrupleGenerator.cpp src/codeGen/Quadruple.h src/codeGen/BasicBlock.h src/Info.h src/InfoList.h src/Absyn.h src/codeGen/Variable.h src/Compiler.h src/codeGen/QuadrupleGenerator.h
${
CC
}
${
CCFLAGS
}
-c
src/codeGen/QuadrupleGenerator.cpp
Latte.o
:
src/Latte.cpp src/Parser.h src/Printer.h src/Absyn.h src/ParseError.h src/TypeCheck.h src/Compiler.h src/Info.h src/InfoList.h src/codeGen/QuadrupleGenerator.h
${
CC
}
${
CCFLAGS
}
-c
src/Latte.cpp
lib/runtime.o
:
lib/runtime.c Makefile
...
...
src/Compiler.cpp
View file @
f63ff4e9
...
...
@@ -21,7 +21,7 @@ void Compiler::externalCommand(std::filesystem::path lat) {
system
(
cmd
.
data
());
}
st
d
::
st
ring
Compiler
::
compile
(
Visitable
*
v
)
{
string
Compiler
::
compile
(
Visitable
*
v
)
{
buf
<<
".globl _start
\n
"
".globl exit
\n
"
...
...
@@ -32,19 +32,19 @@ std::string Compiler::compile(Visitable *v) {
" pushl %eax
\n
"
" call exit
\n
"
;
for
(
auto
c
:
scope
->
classes
)
{
for
(
const
auto
&
c
:
scope
->
classes
)
{
c
->
calculateSize
();
}
for
(
auto
f
:
scope
->
functions
)
{
for
(
const
auto
&
f
:
scope
->
functions
)
{
compileFunction
(
f
);
}
return
buf
.
str
();
}
void
Compiler
::
compileFunction
(
FunctionInfoPtr
f
)
{
st
d
::
st
ring
name
=
mangleFunctionName
(
f
);
void
Compiler
::
compileFunction
(
const
FunctionInfoPtr
&
f
)
{
string
name
=
mangleFunctionName
(
f
);
buf
<<
".globl
\"
"
<<
name
<<
"
\"\n
"
;
if
(
!
f
->
block
)
return
;
...
...
@@ -53,533 +53,12 @@ void Compiler::compileFunction(FunctionInfoPtr f) {
// c++ thiscall ecx, stack right-to-left (push c, push b, push a)
buf
<<
"
\"
"
<<
name
<<
"
\"
:
\n
"
;
scope
->
currentFunction
=
f
;
block
=
make_shared
<
BasicBlock
>
();
f
->
block
->
accept
(
this
);
int
id
=
1
;
for
(
auto
v
:
vars
)
{
if
(
v
->
constExpr
&&
!
v
->
info
)
{
v
->
name
=
std
::
to_string
(
v
->
val
);
continue
;
}
v
->
name
=
"@"
+
std
::
to_string
(
id
);
if
(
v
->
info
)
{
v
->
name
+=
"."
+
v
->
info
->
name
+
":"
+
to_string
(
v
->
info
->
lineLocation
);
}
id
++
;
}
flushBasicBlock
();
block
=
nullptr
;
for
(
auto
b
:
blocks
)
{
b
->
finishQuads
();
}
int
label
=
1
;
for
(
auto
b
:
blocks
)
{
for
(
auto
q
:
b
->
quads
)
{
if
(
auto
l
=
dynamic_pointer_cast
<
QLabel
>
(
q
))
{
if
(
!
l
->
label
.
empty
())
l
->
label
=
to_string
(
label
++
)
+
"_"
+
l
->
label
;
else
l
->
label
=
to_string
(
label
++
);
}
}
}
auto
blocks
=
quadGen
.
compileFunction
(
f
);
for
(
auto
b
:
blocks
)
{
for
(
auto
q
:
b
->
quads
)
{
for
(
const
auto
&
b
:
blocks
)
{
for
(
const
auto
&
q
:
b
->
quads
)
{
buf
<<
q
->
toString
()
<<
endl
;
}
}
for
(
auto
v
:
vars
)
{
if
(
v
->
info
)
v
->
info
->
loc
=
nullptr
;
}
vars
.
clear
();
blocks
.
clear
();
scope
->
currentFunction
=
nullptr
;
}
/*
- kiedy przechodzę między blokami:
- pierwsze wejście w while/fora: ustawienie używanych wartości w pętli w zależności od ostatnich wartości przed pętlą
- dump przed wejściem w stmt fora, dump po sparsowaniu fora
- różnice ustawić w bloku przed i tak samo za nim
- if: przed ifem dump, za ifem dorobić else i ustawić diff
- ifelse: przed ifem dump, w środku dump, po elsie dump
- wszystkie poza zmienionymi w bloku ustawiamy na koniec bloku
wskazówki do implementacji:
- w momencie przypisywania do zmiennej lokalnej chcemy powiadomić najświeższy detektor zmian lokalnych
- po zakończeniu bloku detektor zmian odpowiednio poprzypisuje w pożądanych miejcach odpowiednie definicje
- po zakończeniu bloku detektor powiadomi kolejny z rzędu detektor o najnowszych instancjach zmienionych zmiennych
- detektor powinien działać ponad blokami prostymi
funkcje detektora:
- dodanie zmiennej VarInfoPtr do zbioru, przyporządkowanie jej najnowszej definicji (i zapamiętanie oryginalnej)
- umiejętność porównania dwóch zbiorów poprzez iterację
- każdy element który występuje tylko w jednym
- para jeśli el. występuje w obu zbiorach
implementacja detektora:
- map<VarInfoPtr, pair<orig, new>>
dalej: << i >> dla BB
porobić graf BB
złapać blocki i podumpować envy dookoła flow
dopisać sumę dumpów
*/
BasicBlockPtr
Compiler
::
flushBasicBlock
()
{
auto
ret
=
block
;
if
(
block
)
{
blocks
.
emplace_back
(
block
);
flushLastQuad
();
}
block
=
make_shared
<
BasicBlock
>
();
return
ret
;
}
VariableLayout
Compiler
::
captureEnv
()
{
VariableLayout
ret
;
BindingPtr
b
=
scope
->
currentBinding
;
while
(
b
)
{
for
(
const
auto
&
info
:
b
->
variables
)
{
if
(
info
->
isInstanceVariable
())
continue
;
if
(
info
->
loc
)
{
ret
.
add
(
info
);
}
}
b
=
b
->
getParent
();
}
return
ret
;
}
/// expressions
void
Compiler
::
visitEVar
(
EVar
*
p
)
{
lastVar
=
alloc
(
p
->
pident_
->
var
.
lock
());
}
void
Compiler
::
visitELitInt
(
ELitInt
*
p
)
{
lastVar
=
alloc
(
p
->
integer_
);
}
void
Compiler
::
visitELitTrue
(
ELitTrue
*
p
)
{
lastVar
=
alloc
(
1
);
}
void
Compiler
::
visitELitFalse
(
ELitFalse
*
p
)
{
lastVar
=
alloc
(
0
);
}
void
Compiler
::
visitEString
(
EString
*
p
)
{
// TODO: zrobic liste stringow per app
lastVar
=
alloc
();
}
void
Compiler
::
visitNullCast
(
NullCast
*
p
)
{
lastVar
=
alloc
(
0
);
}
// unary ops
void
Compiler
::
visitNeg
(
Neg
*
p
)
{
auto
var
=
evalExpr
(
p
->
expr_
);
lastVar
=
alloc
();
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Neg
,
var
);
}
void
Compiler
::
visitNot
(
Not
*
p
)
{
auto
var
=
evalExpr
(
p
->
expr_
);
lastVar
=
alloc
();
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Not
,
var
);
}
// binary ops
void
Compiler
::
visitEMul
(
EMul
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
p
->
mulop_
->
accept
(
this
);
addQuad
<
QAssign
>
(
lastVar
,
l
,
op
,
r
);
}
void
Compiler
::
visitEAdd
(
EAdd
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
p
->
addop_
->
accept
(
this
);
addQuad
<
QAssign
>
(
lastVar
,
l
,
op
,
r
);
}
void
Compiler
::
visitERel
(
ERel
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
p
->
relop_
->
accept
(
this
);
addQuad
<
QAssign
>
(
lastVar
,
l
,
op
,
r
);
}
// lazy bools
void
Compiler
::
visitEAnd
(
EAnd
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
labelLeft
=
make_shared
<
QLabel
>
(
"use_left"
);
auto
labelAfter
=
make_shared
<
QLabel
>
(
"end_and"
);
addQuad
<
QJumpCond
>
(
labelLeft
,
Op
::
Not
,
l
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Copy
,
r
);
addQuad
<
QJump
>
(
labelAfter
);
addQuad
(
labelLeft
);
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Copy
,
alloc
(
0
));
addQuad
(
labelAfter
);
}
void
Compiler
::
visitEOr
(
EOr
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
labelLeft
=
make_shared
<
QLabel
>
(
"use_left"
);
auto
labelAfter
=
make_shared
<
QLabel
>
(
"end_or"
);
addQuad
<
QJumpCond
>
(
labelLeft
,
Op
::
Copy
,
l
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Copy
,
r
);
addQuad
<
QJump
>
(
labelAfter
);
addQuad
(
labelLeft
);
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Copy
,
alloc
(
1
));
addQuad
(
labelAfter
);
}
// complex extensions
void
Compiler
::
visitEIndexAcc
(
EIndexAcc
*
p
)
{
auto
lhs
=
evalExpr
(
p
->
expr_1
);
auto
index
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
auto
type
=
dynamic_pointer_cast
<
Array
>
(
lhs
->
type
);
if
(
!
type
)
{
throw
ParseError
(
"compiler evalExpr Variable has no Array type"
,
p
->
expr_1
);
}
if
(
!
type
->
type_
)
{
throw
ParseError
(
"compiler evalExpr Variable is Array of no type"
,
p
->
expr_1
);
}
if
(
type
->
type_
->
size
()
>
4
)
{
// calculate quantifier, we multiply index because size is larger than 4
auto
q
=
alloc
(
type
->
type_
->
size
()
/
4
);
// calculate var = index * quantifier
addQuad
<
QAssign
>
(
lastVar
,
index
,
Op
::
Mul
,
q
);
// allocate new lastVar, index is now calculated multiplied index
index
=
alloc
();
swap
(
index
,
lastVar
);
}
auto
quad
=
make_shared
<
QAccess
>
(
lastVar
,
lhs
,
index
,
4
,
0
);
addQuad
(
quad
);
}
void
Compiler
::
visitEClsMmbr
(
EClsMmbr
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_
);
auto
var
=
p
->
pident_
->
var
.
lock
();
assert
(
var
);
// it cannot be function, as function might only be used in EApp and are handled directly there
assert
(
!
var
->
toFunction
());
// Array length calculation works because of arrayLengthVar that has offset 0
size_t
offset
=
var
->
offset
;
if
(
dynamic_cast
<
EIndexAcc
*>
(
p
->
expr_
))
{
// opt if EIndexAcc is used inside visitEClsMmbr
auto
access
=
dynamic_pointer_cast
<
QAccess
>
(
block
->
quads
.
back
());
access
->
access
.
offset
+=
offset
;
l
->
info
=
var
;
lastVar
=
l
;
}
else
{
lastVar
=
alloc
(
var
);
auto
quad
=
make_shared
<
QAccess
>
(
lastVar
,
l
,
alloc
(
0
),
0
,
offset
);
addQuad
(
quad
);
}
}
void
Compiler
::
visitEApp
(
EApp
*
p
)
{
auto
funType
=
static_pointer_cast
<
Fun
>
(
p
->
expr_
->
type
);
FunctionInfoPtr
info
;
VariablePtr
self
;
if
(
auto
mem
=
dynamic_cast
<
EClsMmbr
*>
(
p
->
expr_
))
{
// call tab[i].fun()
// call obj.fun()
self
=
evalExpr
(
mem
->
expr_
);
info
=
static_pointer_cast
<
FunctionInfo
>
(
mem
->
pident_
->
var
.
lock
());
}
else
if
(
auto
ident
=
dynamic_cast
<
EVar
*>
(
p
->
expr_
))
{
auto
klass
=
scope
->
currentFunction
->
klass
.
lock
();
info
=
static_pointer_cast
<
FunctionInfo
>
(
ident
->
pident_
->
var
.
lock
());
auto
otherClass
=
info
->
klass
.
lock
();
if
(
otherClass
)
{
// call fun() = self.fun()
assert
(
otherClass
==
klass
);
auto
binding
=
scope
->
currentFunction
->
binding
.
lock
();
assert
(
binding
);
auto
selfInfo
=
binding
->
variables
.
local
(
"self"
);
assert
(
selfInfo
);
self
=
alloc
(
selfInfo
);
}
else
{
// call main()
}
}
else
{
throw
ParseError
(
"Unimplemented EApp instantiation (neither EClsMmbr nor EVar"
,
p
);
}
int
i
=
1
;
for
(
auto
param
:
*
p
->
listexpr_
)
{
auto
var
=
evalExpr
(
param
);
addQuad
<
QParam
>
(
var
,
i
++
);
}
if
(
self
)
{
addQuad
<
QParam
>
(
self
,
0
);
}
lastVar
=
alloc
();
addQuad
<
QCall
>
(
lastVar
,
info
,
i
,
self
);
}
void
Compiler
::
visitENewArray
(
ENewArray
*
p
)
{
// allocate enough memory with calloc, if it is class then init each entry...
auto
type
=
p
->
type_
;
size_t
size
=
type
->
size
();
std
::
string
virtSymbol
;
if
(
auto
klass
=
dynamic_cast
<
ClassT
*>
(
type
))
{
auto
info
=
klass
->
pident_
->
var
.
lock
()
->
toClass
();
size
=
info
->
size
;
virtSymbol
=
getVirtName
(
info
);
}
auto
count
=
evalExpr
(
p
->
expr_
);
lastVar
=
alloc
();
addQuad
<
QAlloc
>
(
lastVar
,
size
,
virtSymbol
,
count
);
}
void
Compiler
::
visitENewClass
(
ENewClass
*
p
)
{
// allocate enough memory with calloc, setup virt table pointer.
auto
info
=
p
->
pident_
->
var
.
lock
()
->
toClass
();
size_t
size
=
info
->
size
;
std
::
string
virtSymbol
=
getVirtName
(
info
);
lastVar
=
alloc
();
addQuad
<
QAlloc
>
(
lastVar
,
size
,
virtSymbol
);
}
/// statements
void
Compiler
::
visitInit
(
Init
*
p
)
{
auto
info
=
p
->
pident_
->
var
.
lock
();
assert
(
info
);
auto
var
=
evalExpr
(
p
->
expr_
);
addQuad
<
QAssign
>
(
alloc
(
info
),
Op
::
Copy
,
var
);
}
void
Compiler
::
assign
(
Expr
*
lval
,
VariablePtr
val
)
{
auto
dest
=
evalLVal
(
lval
);
if
(
dest
->
info
&&
dest
->
info
->
isInstanceVariable
())
{
// instance variable, need to write it to memory
auto
quad
=
dynamic_pointer_cast
<
QAccess
>
(
lastQuad
);
assert
(
quad
);
auto
loc
=
quad
->
access
;
lastQuad
=
nullptr
;
addQuad
<
QWrite
>
(
loc
,
val
);
}
else
{
// local variable - only assign
addQuad
<
QAssign
>
(
dest
,
Op
::
Copy
,
val
);
}
}
void
Compiler
::
visitAss
(
Ass
*
p
)
{
auto
val
=
evalExpr
(
p
->
expr_2
);
assign
(
p
->
expr_1
,
val
);
}
void
Compiler
::
visitIncr
(
Incr
*
p
)
{
auto
lhs
=
evalExpr
(
p
->
expr_
);
auto
tmp
=
alloc
();
addQuad
<
QAssign
>
(
tmp
,
lhs
,
Op
::
Plus
,
alloc
(
1
));
assign
(
p
->
expr_
,
tmp
);
}
void
Compiler
::
visitDecr
(
Decr
*
p
)
{
auto
lhs
=
evalExpr
(
p
->
expr_
);
auto
tmp
=
alloc
();
addQuad
<
QAssign
>
(
tmp
,
lhs
,
Op
::
Minus
,
alloc
(
1
));
assign
(
p
->
expr_
,
tmp
);
}
// flow control
void
Compiler
::
visitRet
(
Ret
*
p
)
{
auto
var
=
evalExpr
(
p
->
expr_
);
addQuad
<
QReturn
>
(
var
);
flushBasicBlock
();
}
void
Compiler
::
visitVRet
(
VRet
*
p
)
{
addQuad
<
QReturn
>
(
nullptr
);
flushBasicBlock
();
}
void
Compiler
::
visitCond
(
Cond
*
p
)
{
compileCond
(
p
->
expr_
,
p
->
stmt_
,
nullptr
);
}
void
Compiler
::
visitCondElse
(
CondElse
*
p
)
{
compileCond
(
p
->
expr_
,
p
->
stmt_1
,
p
->
stmt_2
);
}
void
Compiler
::
compileCond
(
Expr
*
expr_
,
Stmt
*
stmt_1
,
Stmt
*
stmt_2
)
{
auto
elseBranch
=
make_shared
<
QLabel
>
(
"else"
);
auto
after
=
make_shared
<
QLabel
>
(
"end_else"
);
auto
var
=
evalExpr
(
expr_
);
addQuad
<
QJumpCond
>
(
elseBranch
,
Op
::
Not
,
var
);
auto
beforeBlock
=
flushBasicBlock
();
// possible jump -> else
auto
env1
=
captureEnv
(),
env2
=
env1
;
stmt_1
->
accept
(
this
);
addQuad
<
QJump
>
(
after
);
auto
stmt1Block
=
flushBasicBlock
();
// jump -> after
env1
.
capture
();
env1
.
revert
();
addQuad
(
elseBranch
);
if
(
stmt_2
)
{
stmt_2
->
accept
(
this
);
}
auto
stmt2Block
=
flushBasicBlock
();
// jump <- cond
env2
.
capture
();
addQuad
(
after
);
beforeBlock
->
append
(
stmt1Block
);
beforeBlock
->
append
(
stmt2Block
);
stmt1Block
->
append
(
block
);
stmt2Block
->
append
(
block
);
merge2Envs
(
&
env1
,
stmt1Block
,
&
env2
,
stmt2Block
);
}
void
Compiler
::
merge2Envs
(
VariableLayout
*
env1
,
BasicBlockPtr
b1
,
VariableLayout
*
env2
,
BasicBlockPtr
b2
)
{
for
(
int
i
=
0
;
i
<
2
;
i
++
)
{
for
(
const
auto
&
p1
:
env1
->
changes
)
{
if
(
p1
.
second
.
first
==
p1
.
second
.
second
)
continue
;
auto
info
=
p1
.
first
;
auto
it
=
env2
->
changes
.
find
(
info
);
if
(
it
!=
env2
->
changes
.
end
())
{
auto
p2
=
*
it
;
// variables have been already merged
if
(
p1
.
second
.
first
==
p2
.
second
.
second
)
continue
;
info
->
loc
=
nullptr
;
auto
merged
=
alloc
(
info
);
// assign both versions to merged variable location
b1
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
merged
,
Op
::
Copy
,
p1
.
second
.
second
));
b2
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
merged
,
Op
::
Copy
,
p2
.
second
.
second
));
}
else
{
// copy changes to another block that did not touch var
b2
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
p1
.
second
.
second
,
Op
::
Copy
,
p1
.
second
.
first
));
}
}
swap
(
env1
,
env2
);
swap
(
b1
,
b2
);
}
}
void
Compiler
::
visitWhile
(
While
*
p
)
{
auto
cond
=
make_shared
<
QLabel
>
(
"cond"
);
addQuad
<
QJump
>
(
cond
);
auto
beforeBlock
=
flushBasicBlock
();
// jump <- loop -> cond
auto
loop
=
make_shared
<
QLabel
>
(
"loop"
);
addQuad
(
loop
);
// jump <- loop
// hook env
auto
env1
=
captureEnv
();
// produce all variables hooks
for
(
const
auto
&
change
:
env1
.
changes
)
{
auto
info
=
change
.
first
;
info
->
loc
=
nullptr
;
alloc
(
info
);
}
// save hooks for later
env1
.
capture
();
// env2 starts with hooked variables
auto
env2
=
captureEnv
();
p
->
stmt_
->
accept
(
this
);
auto
loopBlock
=
flushBasicBlock
();
// jump <- cond
addQuad
(
cond
);
// env2 contains changed hooks
env2
.
capture
();
// restore env1 pre-hook variables
env1
.
revert
();
for
(
auto
p
:
env2
.
changes
)
{
auto
info
=
p
.
first
;
auto
x1
=
p
.
second
.
first
;
auto
x2
=
p
.
second
.
second
;
// save hooks if used
info
->
loc
=
x1
;
// transition from pre-hook to hooked var [before -> cond]
beforeBlock
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
x1
,
Op
::
Copy
,
env1
.
changes
[
info
].
first
));
// transition from loop var to hooked var [loop -> cond]
loopBlock
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
x1
,
Op
::
Copy
,
x2
));
}
// expr uses pre-hook variables iff unused in loop
auto
var
=
evalExpr
(
p
->
expr_
);
addQuad
<
QJumpCond
>
(
loop
,
Op
::
Copy
,
var
);
auto
condBlock
=
flushBasicBlock
();
// jump -> loop
// next block is ready to use updated variables
beforeBlock
->
append
(
condBlock
);
condBlock
->
append
(
loopBlock
);
condBlock
->
append
(
block
);
}
void
Compiler
::
visitSExp
(
SExp
*
p
)
{
evalExpr
(
p
->
expr_
);
}
void
Compiler
::
visitForEach
(
ForEach
*
p
)
{
auto
tab
=
evalExpr
(
p
->
expr_
);
throw
ParseError
(
"Unimplemented instruction!"
,
p
);
// TODO: implement
}
void
Compiler
::
visitBlk
(
Blk
*
blk
)
{
scope
->
currentBinding
=
blk
->
getBinding
();
Skeleton
::
visitBlk
(
blk
);
scope
->
currentBinding
=
scope
->
currentBinding
->
getParent
();
}
src/Compiler.h
View file @
f63ff4e9
...
...
@@ -11,157 +11,35 @@
#include "Info.h"
#include "codeGen/Quadruple.h"
#include "codeGen/BasicBlock.h"
#include "codeGen/QuadrupleGenerator.h"
using
Op
=
Quadruple
::
Op
;
class
Compiler
:
public
Skeleton
{
class
Compiler
{
public:
Compiler
(
const
std
::
string
&
f
,
shared_ptr
<
Scope
>
s
)
:
file
(
f
),
buf
(),
scope
(
std
::
move
(
s
))
{};
std
::
string
compile
(
Visitable
*
v
);
Compiler
(
const
std
::
string
&
f
,
shared_ptr
<
Scope
>
s
)
:
file
(
f
),
buf
(),
scope
(
s
),
quadGen
(
std
::
move
(
s
))
{};
static
const
std
::
string
extension
;
static
void
externalCommand
(
std
::
filesystem
::
path
file
);
string
compile
(
Visitable
*
v
);
static
std
::
string
getVirtName
(
const
ClassInfoPtr
&
c
)
{
return
c
->
name
+
":virt_table"
;
}
private:
std
::
filesystem
::
path
file
;
std
::
stringstream
buf
;
shared_ptr
<
Scope
>
scope
;
vector
<
VariablePtr
>
vars
;
vector
<
BasicBlockPtr
>
blocks
;
Quadruple
::
Op
op
;
BasicBlockPtr
block
;
VariablePtr
lastVar
;
int
lineno
;
void
compileFunction
(
FunctionInfoPtr
f
);
VariablePtr
evalLVal
(
Visitable
*
expr
)
{
auto
info
=
evalExpr
(
expr
)
->
info
;
if
(
!
info
)
{
throw
ParseError
(
"LValue expected"
,
expr
);
}
info
->
loc
=
nullptr
;
return
alloc
(
info
);
}
QuadrupleGenerator
quadGen
;
VariablePtr
evalExpr
(
Visitable
*
expr
)
{
if
(
!
expr
)
throw
runtime_error
(
"No expr to eval"
);
lineno
=
expr
->
lineno
;
lastVar
=
nullptr
;
try
{
expr
->
accept
(
this
);
}
catch
(
const
ParseError
&
err
)
{
throw
ParseError
(
err
,
expr
);
}
if
(
!
lastVar
)
throw
ParseError
(
"No variable found"
,
expr
);
auto
ret
=
lastVar
;
lastVar
=
nullptr
;
return
ret
;
};
void
compileFunction
(
const
FunctionInfoPtr
&
f
);
static
std
::
string
mangleFunctionName
(
const
FunctionInfoPtr
&
f
)
{
if
(
auto
c
=
f
->
klass
.
lock
())
{
return
c
->
name
+
"::"
+
f
->
name
;
}
return
f
->
name
;
};
static
std
::
string
getVirtName
(
const
ClassInfoPtr
&
c
)
{
return
c
->
name
+
":virt_table"
;
};
VariablePtr
alloc
(
const
VarInfoPtr
&
info
)
{
if
(
info
->
loc
)
{
return
info
->
loc
;
}
auto
v
=
make_shared
<
Variable
>
(
info
);
vars
.
emplace_back
(
v
);
if
(
!
info
->
isInstanceVariable
())
{
info
->
loc
=
v
;
}
return
v
;
}
template
<
typename
...
Args
>
VariablePtr
alloc
(
Args
...
args
)
{
auto
v
=
make_shared
<
Variable
>
(
args
...);
vars
.
emplace_back
(
v
);
return
v
;
}
template
<
typename
T
,
typename
...
Args
>
QuadruplePtr
addQuad
(
Args
...
args
)
{
return
addQuad
(
make_shared
<
T
>
(
args
...));
}
QuadruplePtr
addQuad
(
QuadruplePtr
quad
)
{
quad
->
lineno
=
lineno
;
flushLastQuad
();
lastQuad
=
quad
;
return
quad
;
}
QuadruplePtr
lastQuad
;
void
flushLastQuad
()
{
if
(
lastQuad
)
{
block
->
quads
.
emplace_back
(
lastQuad
);
lastQuad
=
nullptr
;
}
}
BasicBlockPtr
flushBasicBlock
();
void
assign
(
Expr
*
lval
,
VariablePtr
val
);
VariableLayout
captureEnv
();
void
merge2Envs
(
VariableLayout
*
env1
,
BasicBlockPtr
b1
,
VariableLayout
*
env2
,
BasicBlockPtr
b2
);
void
compileCond
(
Expr
*
cond
,
Stmt
*
stmt1
,
Stmt
*
stmt2
);
void
visitEVar
(
EVar
*
p
)
override
;
void
visitEIndexAcc
(
EIndexAcc
*
p
)
override
;
void
visitEClsMmbr
(
EClsMmbr
*
p
)
override
;
void
visitEApp
(
EApp
*
p
)
override
;
void
visitELitInt
(
ELitInt
*
p
)
override
;
void
visitELitTrue
(
ELitTrue
*
p
)
override
;
void
visitELitFalse
(
ELitFalse
*
p
)
override
;
void
visitEString
(
EString
*
p
)
override
;
void
visitENewArray
(
ENewArray
*
p
)
override
;
void
visitENewClass
(
ENewClass
*
p
)
override
;
void
visitNullCast
(
NullCast
*
p
)
override
;
void
visitNeg
(
Neg
*
p
)
override
;
void
visitNot
(
Not
*
p
)
override
;
void
visitEMul
(
EMul
*
p
)
override
;
void
visitEAdd
(
EAdd
*
p
)
override
;
void
visitERel
(
ERel
*
p
)
override
;
void
visitEAnd
(
EAnd
*
p
)
override
;
void
visitEOr
(
EOr
*
p
)
override
;
void
visitBlk
(
Blk
*
p
)
override
;
void
visitInit
(
Init
*
p
)
override
;
void
visitAss
(
Ass
*
p
)
override
;
void
visitIncr
(
Incr
*
p
)
override
;
void
visitDecr
(
Decr
*
p
)
override
;
void
visitRet
(
Ret
*
p
)
override
;
void
visitVRet
(
VRet
*
p
)
override
;
void
visitCond
(
Cond
*
p
)
override
;
void
visitCondElse
(
CondElse
*
p
)
override
;
void
visitWhile
(
While
*
p
)
override
;
void
visitSExp
(
SExp
*
p
)
override
;
void
visitForEach
(
ForEach
*
p
)
override
;
void
visitPlus
(
Plus
*
p
)
override
{
op
=
Op
::
Plus
;
};
void
visitMinus
(
Minus
*
p
)
override
{
op
=
Op
::
Minus
;
};
void
visitTimes
(
Times
*
p
)
override
{
op
=
Op
::
Mul
;
};
void
visitDiv
(
Div
*
p
)
override
{
op
=
Op
::
Div
;
};
void
visitMod
(
Mod
*
p
)
override
{
op
=
Op
::
Mod
;
};
void
visitLTH
(
LTH
*
p
)
override
{
op
=
Op
::
LT
;
};
void
visitLE
(
LE
*
p
)
override
{
op
=
Op
::
LE
;
};
void
visitGTH
(
GTH
*
p
)
override
{
op
=
Op
::
GT
;
};
void
visitGE
(
GE
*
p
)
override
{
op
=
Op
::
GE
;
};
void
visitEQU
(
EQU
*
p
)
override
{
op
=
Op
::
EQ
;
};
void
visitNE
(
NE
*
p
)
override
{
op
=
Op
::
NEQ
;
};
};
#endif
src/codeGen/QuadrupleGenerator.cpp
0 → 100644
View file @
f63ff4e9
//
// Created by zygzagz on 05.01.2021.
//
#include <cassert>
#include <iostream>
#include <filesystem>
#include "Quadruple.h"
#include "../Compiler.h"
#include "QuadrupleGenerator.h"
vector
<
BasicBlockPtr
>
QuadrupleGenerator
::
compileFunction
(
FunctionInfoPtr
f
)
{
if
(
!
f
->
block
)
return
{};
scope
->
currentFunction
=
f
;
block
=
make_shared
<
BasicBlock
>
();
f
->
block
->
accept
(
this
);
int
id
=
1
;
for
(
auto
v
:
vars
)
{
if
(
v
->
constExpr
&&
!
v
->
info
)
{
v
->
name
=
to_string
(
v
->
val
);
continue
;
}
v
->
name
=
"@"
+
to_string
(
id
);
if
(
v
->
info
)
{
v
->
name
+=
"."
+
v
->
info
->
name
+
":"
+
to_string
(
v
->
info
->
lineLocation
);
}
id
++
;
}
flushBasicBlock
();
block
=
nullptr
;
for
(
auto
b
:
blocks
)
{
b
->
finishQuads
();
}
int
label
=
1
;
for
(
auto
b
:
blocks
)
{
for
(
auto
q
:
b
->
quads
)
{
if
(
auto
l
=
dynamic_pointer_cast
<
QLabel
>
(
q
))
{
if
(
!
l
->
label
.
empty
())
l
->
label
=
to_string
(
label
++
)
+
"_"
+
l
->
label
;
else
l
->
label
=
to_string
(
label
++
);
}
}
}
for
(
auto
v
:
vars
)
{
if
(
v
->
info
)
v
->
info
->
loc
=
nullptr
;
}
vars
.
clear
();
vector
<
BasicBlockPtr
>
ret
;
blocks
.
swap
(
ret
);
scope
->
currentFunction
=
nullptr
;
return
ret
;
}
/*
- kiedy przechodzę między blokami:
- pierwsze wejście w while/fora: ustawienie używanych wartości w pętli w zależności od ostatnich wartości przed pętlą
- dump przed wejściem w stmt fora, dump po sparsowaniu fora
- różnice ustawić w bloku przed i tak samo za nim
- if: przed ifem dump, za ifem dorobić else i ustawić diff
- ifelse: przed ifem dump, w środku dump, po elsie dump
- wszystkie poza zmienionymi w bloku ustawiamy na koniec bloku
wskazówki do implementacji:
- w momencie przypisywania do zmiennej lokalnej chcemy powiadomić najświeższy detektor zmian lokalnych
- po zakończeniu bloku detektor zmian odpowiednio poprzypisuje w pożądanych miejcach odpowiednie definicje
- po zakończeniu bloku detektor powiadomi kolejny z rzędu detektor o najnowszych instancjach zmienionych zmiennych
- detektor powinien działać ponad blokami prostymi
funkcje detektora:
- dodanie zmiennej VarInfoPtr do zbioru, przyporządkowanie jej najnowszej definicji (i zapamiętanie oryginalnej)
- umiejętność porównania dwóch zbiorów poprzez iterację
- każdy element który występuje tylko w jednym
- para jeśli el. występuje w obu zbiorach
implementacja detektora:
- map<VarInfoPtr, pair<orig, new>>
dalej: << i >> dla BB
porobić graf BB
złapać blocki i podumpować envy dookoła flow
dopisać sumę dumpów
*/
BasicBlockPtr
QuadrupleGenerator
::
flushBasicBlock
()
{
auto
ret
=
block
;
if
(
block
)
{
blocks
.
emplace_back
(
block
);
flushLastQuad
();
}
block
=
make_shared
<
BasicBlock
>
();
return
ret
;
}
VariableLayout
QuadrupleGenerator
::
captureEnv
()
{
VariableLayout
ret
;
BindingPtr
b
=
scope
->
currentBinding
;
while
(
b
)
{
for
(
const
auto
&
info
:
b
->
variables
)
{
if
(
info
->
isInstanceVariable
())
continue
;
if
(
info
->
loc
)
{
ret
.
add
(
info
);
}
}
b
=
b
->
getParent
();
}
return
ret
;
}
/// expressions
void
QuadrupleGenerator
::
visitEVar
(
EVar
*
p
)
{
lastVar
=
alloc
(
p
->
pident_
->
var
.
lock
());
}
void
QuadrupleGenerator
::
visitELitInt
(
ELitInt
*
p
)
{
lastVar
=
alloc
(
p
->
integer_
);
}
void
QuadrupleGenerator
::
visitELitTrue
(
ELitTrue
*
p
)
{
lastVar
=
alloc
(
1
);
}
void
QuadrupleGenerator
::
visitELitFalse
(
ELitFalse
*
p
)
{
lastVar
=
alloc
(
0
);
}
void
QuadrupleGenerator
::
visitEString
(
EString
*
p
)
{
// TODO: zrobic liste stringow per app
lastVar
=
alloc
();
}
void
QuadrupleGenerator
::
visitNullCast
(
NullCast
*
p
)
{
lastVar
=
alloc
(
0
);
}
void
QuadrupleGenerator
::
visitNeg
(
Neg
*
p
)
{
auto
var
=
evalExpr
(
p
->
expr_
);
lastVar
=
alloc
();
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Neg
,
var
);
}
void
QuadrupleGenerator
::
visitNot
(
Not
*
p
)
{
auto
var
=
evalExpr
(
p
->
expr_
);
lastVar
=
alloc
();
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Not
,
var
);
}
void
QuadrupleGenerator
::
visitEMul
(
EMul
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
p
->
mulop_
->
accept
(
this
);
addQuad
<
QAssign
>
(
lastVar
,
l
,
op
,
r
);
}
void
QuadrupleGenerator
::
visitEAdd
(
EAdd
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
p
->
addop_
->
accept
(
this
);
addQuad
<
QAssign
>
(
lastVar
,
l
,
op
,
r
);
}
void
QuadrupleGenerator
::
visitERel
(
ERel
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
p
->
relop_
->
accept
(
this
);
addQuad
<
QAssign
>
(
lastVar
,
l
,
op
,
r
);
}
void
QuadrupleGenerator
::
visitEAnd
(
EAnd
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
labelLeft
=
make_shared
<
QLabel
>
(
"use_left"
);
auto
labelAfter
=
make_shared
<
QLabel
>
(
"end_and"
);
addQuad
<
QJumpCond
>
(
labelLeft
,
Op
::
Not
,
l
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Copy
,
r
);
addQuad
<
QJump
>
(
labelAfter
);
addQuad
(
labelLeft
);
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Copy
,
alloc
(
0
));
addQuad
(
labelAfter
);
}
void
QuadrupleGenerator
::
visitEOr
(
EOr
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_1
);
auto
labelLeft
=
make_shared
<
QLabel
>
(
"use_left"
);
auto
labelAfter
=
make_shared
<
QLabel
>
(
"end_or"
);
addQuad
<
QJumpCond
>
(
labelLeft
,
Op
::
Copy
,
l
);
auto
r
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Copy
,
r
);
addQuad
<
QJump
>
(
labelAfter
);
addQuad
(
labelLeft
);
addQuad
<
QAssign
>
(
lastVar
,
Op
::
Copy
,
alloc
(
1
));
addQuad
(
labelAfter
);
}
/// complex extensions
void
QuadrupleGenerator
::
visitEIndexAcc
(
EIndexAcc
*
p
)
{
auto
lhs
=
evalExpr
(
p
->
expr_1
);
auto
index
=
evalExpr
(
p
->
expr_2
);
lastVar
=
alloc
();
auto
type
=
dynamic_pointer_cast
<
Array
>
(
lhs
->
type
);
if
(
!
type
)
{
throw
ParseError
(
"compiler evalExpr Variable has no Array type"
,
p
->
expr_1
);
}
if
(
!
type
->
type_
)
{
throw
ParseError
(
"compiler evalExpr Variable is Array of no type"
,
p
->
expr_1
);
}
if
(
type
->
type_
->
size
()
>
4
)
{
// calculate quantifier, we multiply index because size is larger than 4
auto
q
=
alloc
(
type
->
type_
->
size
()
/
4
);
// calculate var = index * quantifier
addQuad
<
QAssign
>
(
lastVar
,
index
,
Op
::
Mul
,
q
);
// allocate new lastVar, index is now calculated multiplied index
index
=
alloc
();
swap
(
index
,
lastVar
);
}
auto
quad
=
make_shared
<
QAccess
>
(
lastVar
,
lhs
,
index
,
4
,
0
);
addQuad
(
quad
);
}
void
QuadrupleGenerator
::
visitEClsMmbr
(
EClsMmbr
*
p
)
{
auto
l
=
evalExpr
(
p
->
expr_
);
auto
var
=
p
->
pident_
->
var
.
lock
();
assert
(
var
);
// it cannot be function, as function might only be used in EApp and are handled directly there
assert
(
!
var
->
toFunction
());
// Array length calculation works because of arrayLengthVar that has offset 0
size_t
offset
=
var
->
offset
;
if
(
dynamic_cast
<
EIndexAcc
*>
(
p
->
expr_
))
{
// opt if EIndexAcc is used inside visitEClsMmbr
auto
access
=
dynamic_pointer_cast
<
QAccess
>
(
block
->
quads
.
back
());
access
->
access
.
offset
+=
offset
;
l
->
info
=
var
;
lastVar
=
l
;
}
else
{
lastVar
=
alloc
(
var
);
auto
quad
=
make_shared
<
QAccess
>
(
lastVar
,
l
,
alloc
(
0
),
0
,
offset
);
addQuad
(
quad
);
}
}
void
QuadrupleGenerator
::
visitEApp
(
EApp
*
p
)
{
auto
funType
=
static_pointer_cast
<
Fun
>
(
p
->
expr_
->
type
);
FunctionInfoPtr
info
;
VariablePtr
self
;
if
(
auto
mem
=
dynamic_cast
<
EClsMmbr
*>
(
p
->
expr_
))
{
// call tab[i].fun()
// call obj.fun()
self
=
evalExpr
(
mem
->
expr_
);
info
=
static_pointer_cast
<
FunctionInfo
>
(
mem
->
pident_
->
var
.
lock
());
}
else
if
(
auto
ident
=
dynamic_cast
<
EVar
*>
(
p
->
expr_
))
{
auto
klass
=
scope
->
currentFunction
->
klass
.
lock
();
info
=
static_pointer_cast
<
FunctionInfo
>
(
ident
->
pident_
->
var
.
lock
());
auto
otherClass
=
info
->
klass
.
lock
();
if
(
otherClass
)
{
// call fun() = self.fun()
assert
(
otherClass
==
klass
);
auto
binding
=
scope
->
currentFunction
->
binding
.
lock
();
assert
(
binding
);
auto
selfInfo
=
binding
->
variables
.
local
(
"self"
);
assert
(
selfInfo
);
self
=
alloc
(
selfInfo
);
}
else
{
// call main()
}
}
else
{
throw
ParseError
(
"Unimplemented EApp instantiation (neither EClsMmbr nor EVar"
,
p
);
}
int
i
=
1
;
for
(
auto
param
:
*
p
->
listexpr_
)
{
auto
var
=
evalExpr
(
param
);
addQuad
<
QParam
>
(
var
,
i
++
);
}
if
(
self
)
{
addQuad
<
QParam
>
(
self
,
0
);
}
lastVar
=
alloc
();
addQuad
<
QCall
>
(
lastVar
,
info
,
i
,
self
);
}
void
QuadrupleGenerator
::
visitENewArray
(
ENewArray
*
p
)
{
// allocate enough memory with calloc, if it is class then init each entry...
auto
type
=
p
->
type_
;
size_t
size
=
type
->
size
();
string
virtSymbol
;
if
(
auto
klass
=
dynamic_cast
<
ClassT
*>
(
type
))
{
auto
info
=
klass
->
pident_
->
var
.
lock
()
->
toClass
();
size
=
info
->
size
;
virtSymbol
=
Compiler
::
getVirtName
(
info
);
}
auto
count
=
evalExpr
(
p
->
expr_
);
lastVar
=
alloc
();
addQuad
<
QAlloc
>
(
lastVar
,
size
,
virtSymbol
,
count
);
}
void
QuadrupleGenerator
::
visitENewClass
(
ENewClass
*
p
)
{
// allocate enough memory with calloc, setup virt table pointer.
auto
info
=
p
->
pident_
->
var
.
lock
()
->
toClass
();
size_t
size
=
info
->
size
;
string
virtSymbol
=
Compiler
::
getVirtName
(
info
);
lastVar
=
alloc
();
addQuad
<
QAlloc
>
(
lastVar
,
size
,
virtSymbol
);
}
/// statements
void
QuadrupleGenerator
::
visitInit
(
Init
*
p
)
{
auto
info
=
p
->
pident_
->
var
.
lock
();
assert
(
info
);
auto
var
=
evalExpr
(
p
->
expr_
);
addQuad
<
QAssign
>
(
alloc
(
info
),
Op
::
Copy
,
var
);
}
void
QuadrupleGenerator
::
assign
(
Expr
*
lval
,
VariablePtr
val
)
{
auto
dest
=
evalLVal
(
lval
);
if
(
dest
->
info
&&
dest
->
info
->
isInstanceVariable
())
{
// instance variable, need to write it to memory
auto
quad
=
dynamic_pointer_cast
<
QAccess
>
(
lastQuad
);
assert
(
quad
);
auto
loc
=
quad
->
access
;
lastQuad
=
nullptr
;
addQuad
<
QWrite
>
(
loc
,
val
);
}
else
{
// local variable - only assign
addQuad
<
QAssign
>
(
dest
,
Op
::
Copy
,
val
);
}
}
void
QuadrupleGenerator
::
visitAss
(
Ass
*
p
)
{
auto
val
=
evalExpr
(
p
->
expr_2
);
assign
(
p
->
expr_1
,
val
);
}
void
QuadrupleGenerator
::
visitIncr
(
Incr
*
p
)
{
auto
lhs
=
evalExpr
(
p
->
expr_
);
auto
tmp
=
alloc
();
addQuad
<
QAssign
>
(
tmp
,
lhs
,
Op
::
Plus
,
alloc
(
1
));
assign
(
p
->
expr_
,
tmp
);
}
void
QuadrupleGenerator
::
visitDecr
(
Decr
*
p
)
{
auto
lhs
=
evalExpr
(
p
->
expr_
);
auto
tmp
=
alloc
();
addQuad
<
QAssign
>
(
tmp
,
lhs
,
Op
::
Minus
,
alloc
(
1
));
assign
(
p
->
expr_
,
tmp
);
}
void
QuadrupleGenerator
::
visitBlk
(
Blk
*
blk
)
{
scope
->
currentBinding
=
blk
->
getBinding
();
Skeleton
::
visitBlk
(
blk
);
scope
->
currentBinding
=
scope
->
currentBinding
->
getParent
();
}
/// flow control
void
QuadrupleGenerator
::
visitRet
(
Ret
*
p
)
{
auto
var
=
evalExpr
(
p
->
expr_
);
addQuad
<
QReturn
>
(
var
);
flushBasicBlock
();
}
void
QuadrupleGenerator
::
visitVRet
(
VRet
*
p
)
{
addQuad
<
QReturn
>
(
nullptr
);
flushBasicBlock
();
}
void
QuadrupleGenerator
::
visitCond
(
Cond
*
p
)
{
compileCond
(
p
->
expr_
,
p
->
stmt_
,
nullptr
);
}
void
QuadrupleGenerator
::
visitCondElse
(
CondElse
*
p
)
{
compileCond
(
p
->
expr_
,
p
->
stmt_1
,
p
->
stmt_2
);
}
void
QuadrupleGenerator
::
compileCond
(
Expr
*
expr_
,
Stmt
*
stmt_1
,
Stmt
*
stmt_2
)
{
auto
elseBranch
=
make_shared
<
QLabel
>
(
"else"
);
auto
after
=
make_shared
<
QLabel
>
(
"end_else"
);
auto
var
=
evalExpr
(
expr_
);
addQuad
<
QJumpCond
>
(
elseBranch
,
Op
::
Not
,
var
);
auto
beforeBlock
=
flushBasicBlock
();
// possible jump -> else
auto
env1
=
captureEnv
(),
env2
=
env1
;
stmt_1
->
accept
(
this
);
addQuad
<
QJump
>
(
after
);
auto
stmt1Block
=
flushBasicBlock
();
// jump -> after
env1
.
capture
();
env1
.
revert
();
addQuad
(
elseBranch
);
if
(
stmt_2
)
{
stmt_2
->
accept
(
this
);
}
auto
stmt2Block
=
flushBasicBlock
();
// jump <- cond
env2
.
capture
();
addQuad
(
after
);
beforeBlock
->
append
(
stmt1Block
);
beforeBlock
->
append
(
stmt2Block
);
stmt1Block
->
append
(
block
);
stmt2Block
->
append
(
block
);
merge2Envs
(
&
env1
,
stmt1Block
,
&
env2
,
stmt2Block
);
}
void
QuadrupleGenerator
::
merge2Envs
(
VariableLayout
*
env1
,
BasicBlockPtr
b1
,
VariableLayout
*
env2
,
BasicBlockPtr
b2
)
{
for
(
int
i
=
0
;
i
<
2
;
i
++
)
{
for
(
const
auto
&
p1
:
env1
->
changes
)
{
if
(
p1
.
second
.
first
==
p1
.
second
.
second
)
continue
;
auto
info
=
p1
.
first
;
auto
it
=
env2
->
changes
.
find
(
info
);
if
(
it
!=
env2
->
changes
.
end
())
{
auto
p2
=
*
it
;
// variables have been already merged
if
(
p1
.
second
.
first
==
p2
.
second
.
second
)
continue
;
info
->
loc
=
nullptr
;
auto
merged
=
alloc
(
info
);
// assign both versions to merged variable location
b1
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
merged
,
Op
::
Copy
,
p1
.
second
.
second
));
b2
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
merged
,
Op
::
Copy
,
p2
.
second
.
second
));
}
else
{
// copy changes to another block that did not touch var
b2
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
p1
.
second
.
second
,
Op
::
Copy
,
p1
.
second
.
first
));
}
}
swap
(
env1
,
env2
);
swap
(
b1
,
b2
);
}
}
void
QuadrupleGenerator
::
visitWhile
(
While
*
expr
)
{
auto
cond
=
make_shared
<
QLabel
>
(
"cond"
);
addQuad
<
QJump
>
(
cond
);
auto
beforeBlock
=
flushBasicBlock
();
// jump <- loop -> cond
auto
loop
=
make_shared
<
QLabel
>
(
"loop"
);
addQuad
(
loop
);
// jump <- loop
// hook env
auto
env1
=
captureEnv
();
// produce all variables hooks
for
(
const
auto
&
change
:
env1
.
changes
)
{
auto
info
=
change
.
first
;
info
->
loc
=
nullptr
;
alloc
(
info
);
}
// save hooks for later
env1
.
capture
();
// env2 starts with hooked variables
auto
env2
=
captureEnv
();
expr
->
stmt_
->
accept
(
this
);
auto
loopBlock
=
flushBasicBlock
();
// jump <- cond
addQuad
(
cond
);
// env2 contains changed hooks
env2
.
capture
();
// restore env1 pre-hook variables
env1
.
revert
();
for
(
const
auto
&
p
:
env2
.
changes
)
{
auto
info
=
p
.
first
;
auto
x1
=
p
.
second
.
first
;
auto
x2
=
p
.
second
.
second
;
// save hooks if used
info
->
loc
=
x1
;
// transition from pre-hook to hooked var [before -> cond]
beforeBlock
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
x1
,
Op
::
Copy
,
env1
.
changes
[
info
].
first
));
// transition from loop var to hooked var [loop -> cond]
loopBlock
->
addJumpInitQuad
(
make_shared
<
QAssign
>
(
x1
,
Op
::
Copy
,
x2
));
}
// expr uses pre-hook variables iff unused in loop
auto
var
=
evalExpr
(
expr
->
expr_
);
addQuad
<
QJumpCond
>
(
loop
,
Op
::
Copy
,
var
);
auto
condBlock
=
flushBasicBlock
();
// jump -> loop
// next block is ready to use updated variables
beforeBlock
->
append
(
condBlock
);
condBlock
->
append
(
loopBlock
);
condBlock
->
append
(
block
);
}
void
QuadrupleGenerator
::
visitSExp
(
SExp
*
p
)
{
evalExpr
(
p
->
expr_
);
}
void
QuadrupleGenerator
::
visitForEach
(
ForEach
*
p
)
{
auto
tab
=
evalExpr
(
p
->
expr_
);
throw
ParseError
(
"ForEach is yet unimplemented!"
,
p
);
// TODO: implement
}
\ No newline at end of file
src/codeGen/QuadrupleGenerator.h
0 → 100644
View file @
f63ff4e9
//
// Created by zygzagz on 05.01.2021.
//
#ifndef ZAD2_QUADRUPLEGENERATOR_H
#define ZAD2_QUADRUPLEGENERATOR_H
#include <filesystem>
#include <utility>
#include "../TypeDefs.h"
#include "../Absyn.h"
#include "../Skeleton.h"
#include "Variable.h"
#include "../ParseError.h"
#include "../Info.h"
#include "Quadruple.h"
#include "BasicBlock.h"
class
QuadrupleGenerator
:
public
Skeleton
{
public:
QuadrupleGenerator
(
shared_ptr
<
Scope
>
s
)
:
lineno
(
0
),
scope
(
std
::
move
(
s
))
{}
vector
<
BasicBlockPtr
>
compileFunction
(
FunctionInfoPtr
f
);
private:
vector
<
VariablePtr
>
vars
;
vector
<
BasicBlockPtr
>
blocks
;
Quadruple
::
Op
op
;
BasicBlockPtr
block
;
VariablePtr
lastVar
;
int
lineno
;
shared_ptr
<
Scope
>
scope
;
VariablePtr
evalLVal
(
Visitable
*
expr
)
{
auto
info
=
evalExpr
(
expr
)
->
info
;
if
(
!
info
)
{
throw
ParseError
(
"LValue expected"
,
expr
);
}
info
->
loc
=
nullptr
;
return
alloc
(
info
);
}
VariablePtr
evalExpr
(
Visitable
*
expr
)
{
if
(
!
expr
)
throw
runtime_error
(
"No expr to eval"
);
lineno
=
expr
->
lineno
;
lastVar
=
nullptr
;
try
{
expr
->
accept
(
this
);
}
catch
(
const
ParseError
&
err
)
{
throw
ParseError
(
err
,
expr
);
}
if
(
!
lastVar
)
throw
ParseError
(
"No variable found"
,
expr
);
auto
ret
=
lastVar
;
lastVar
=
nullptr
;
return
ret
;
}
VariablePtr
alloc
(
const
VarInfoPtr
&
info
)
{
if
(
info
->
loc
)
{
return
info
->
loc
;
}
auto
v
=
make_shared
<
Variable
>
(
info
);
vars
.
emplace_back
(
v
);
if
(
!
info
->
isInstanceVariable
())
{
info
->
loc
=
v
;
}
return
v
;
}
template
<
typename
...
Args
>
VariablePtr
alloc
(
Args
...
args
)
{
auto
v
=
make_shared
<
Variable
>
(
args
...);
vars
.
emplace_back
(
v
);
return
v
;
}
template
<
typename
T
,
typename
...
Args
>
QuadruplePtr
addQuad
(
Args
...
args
)
{
return
addQuad
(
make_shared
<
T
>
(
args
...));
}
QuadruplePtr
addQuad
(
QuadruplePtr
quad
)
{
quad
->
lineno
=
lineno
;
flushLastQuad
();
lastQuad
=
quad
;
return
quad
;
}
QuadruplePtr
lastQuad
;
void
flushLastQuad
()
{
if
(
lastQuad
)
{
block
->
quads
.
emplace_back
(
lastQuad
);
lastQuad
=
nullptr
;
}
}
BasicBlockPtr
flushBasicBlock
();
void
visitPlus
(
Plus
*
p
)
override
{
op
=
Quadruple
::
Op
::
Plus
;
}
void
visitMinus
(
Minus
*
p
)
override
{
op
=
Quadruple
::
Op
::
Minus
;
}
VariableLayout
captureEnv
();
void
visitTimes
(
Times
*
p
)
override
{
op
=
Quadruple
::
Op
::
Mul
;
}
void
visitDiv
(
Div
*
p
)
override
{
op
=
Quadruple
::
Op
::
Div
;
}
void
visitMod
(
Mod
*
p
)
override
{
op
=
Quadruple
::
Op
::
Mod
;
}
void
visitLTH
(
LTH
*
p
)
override
{
op
=
Quadruple
::
Op
::
LT
;
}
void
visitLE
(
LE
*
p
)
override
{
op
=
Quadruple
::
Op
::
LE
;
}
void
visitEVar
(
EVar
*
p
)
override
;
void
visitGTH
(
GTH
*
p
)
override
{
op
=
Quadruple
::
Op
::
GT
;
}
void
visitGE
(
GE
*
p
)
override
{
op
=
Quadruple
::
Op
::
GE
;
}
void
visitELitInt
(
ELitInt
*
p
)
override
;
void
visitEQU
(
EQU
*
p
)
override
{
op
=
Quadruple
::
Op
::
EQ
;
}
void
visitNE
(
NE
*
p
)
override
{
op
=
Quadruple
::
Op
::
NEQ
;
}
void
visitELitTrue
(
ELitTrue
*
p
)
override
;
void
visitELitFalse
(
ELitFalse
*
p
)
override
;
void
visitEString
(
EString
*
p
)
override
;
void
visitNullCast
(
NullCast
*
p
)
override
;
void
visitNeg
(
Neg
*
p
)
override
;
void
visitNot
(
Not
*
p
)
override
;
void
visitEMul
(
EMul
*
p
)
override
;
void
visitEAdd
(
EAdd
*
p
)
override
;
void
visitERel
(
ERel
*
p
)
override
;
void
visitEAnd
(
EAnd
*
p
)
override
;
void
visitEOr
(
EOr
*
p
)
override
;
void
visitEIndexAcc
(
EIndexAcc
*
p
)
override
;
void
visitEClsMmbr
(
EClsMmbr
*
p
)
override
;
void
visitEApp
(
EApp
*
p
)
override
;
void
visitENewArray
(
ENewArray
*
p
)
override
;
void
visitENewClass
(
ENewClass
*
p
)
override
;
void
visitInit
(
Init
*
p
)
override
;
void
assign
(
Expr
*
lval
,
VariablePtr
val
);
void
visitAss
(
Ass
*
p
)
override
;
void
visitIncr
(
Incr
*
p
)
override
;
void
visitDecr
(
Decr
*
p
)
override
;
void
visitRet
(
Ret
*
p
)
override
;
void
visitVRet
(
VRet
*
p
)
override
;
void
visitCond
(
Cond
*
p
)
override
;
void
visitCondElse
(
CondElse
*
p
)
override
;
void
compileCond
(
Expr
*
cond
,
Stmt
*
stmt1
,
Stmt
*
stmt2
);
void
merge2Envs
(
VariableLayout
*
env1
,
BasicBlockPtr
b1
,
VariableLayout
*
env2
,
BasicBlockPtr
b2
);
void
visitWhile
(
While
*
expr
)
override
;
void
visitSExp
(
SExp
*
p
)
override
;
void
visitForEach
(
ForEach
*
p
)
override
;
void
visitBlk
(
Blk
*
p
)
override
;
};
#endif //ZAD2_QUADRUPLEGENERATOR_H
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment