Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Shen, Siran
wacc
Commits
b42a3f3f
Commit
b42a3f3f
authored
Mar 17, 2021
by
徐世桐
Browse files
Merge branch 'master' into develop
parents
b798cdd8
ca5ed482
Changes
29
Show whitespace changes
Inline
Side-by-side
.gitlab-ci.yml
View file @
b42a3f3f
...
...
@@ -10,6 +10,7 @@ stages:
-
build
-
frontend-test
-
backend-test
-
optimise-test
build-job
:
stage
:
build
...
...
@@ -61,3 +62,14 @@ test-execute-valid:
paths
:
-
log/assembly
-
log/output
test-optimise
:
stage
:
optimise-test
script
:
-
echo "compile oprimise sample tests and conpair with given .log result file"
-
./scripts/constantPropagationTest.sh
-
./scripts/extensionValidTest.sh
artifacts
:
paths
:
-
log/assembly
-
log/output
\ No newline at end of file
antlr_config/WACCParser.g4
View file @
b42a3f3f
...
...
@@ -131,8 +131,7 @@ expr : INT_LITER #IntExpr
| expr bop=( '+' | '-' ) expr #ArithmeticExpr
| expr bop=( '>' | '>=' | '<' | '<=' ) expr #CmpExpr
| expr bop=( '==' | '!=' ) expr #EqExpr
| expr '&' expr #BitwiseAndExpr
| expr '|' expr #BitwiseOrExpr
| expr bitop=( '&' | '|' ) expr #BitwiseExpr
| expr '&&' expr #AndExpr
| expr '||' expr #OrExpr
| OPEN_PARENTHESES expr CLOSE_PARENTHESES #ParenExpr
...
...
compile
View file @
b42a3f3f
...
...
@@ -39,4 +39,5 @@ then
fi
# compile the given wacc file here
java
-cp
./bin:./lib/antlr-4.9.1-complete.jar Compiler
$1
$PARSE_ONLY
$PRINT_AST
$OPTIMISE
"--assembly"
$EXECUTE
\ No newline at end of file
# default as using -o1 optimise and generate assembly
java
-cp
./bin:./lib/antlr-4.9.1-complete.jar Compiler
$1
$PARSE_ONLY
$PRINT_AST
$OPTIMISE
"--optimise"
"1"
"--assembly"
$EXECUTE
\ No newline at end of file
scripts/allTest
View file @
b42a3f3f
...
...
@@ -8,3 +8,5 @@
./scripts/semanticCheckerSemanticErr
./scripts/assembleTest.sh
./scripts/executeTest.sh
./scripts/constantPropagation.sh
./scripts/extensionValidTest.sh
\ No newline at end of file
scripts/constant
Evalu
ationTest.sh
→
scripts/constant
Propag
ationTest.sh
View file @
b42a3f3f
#!/bin/bash
VALID_EXAMPLE_DIR
=
"./src/test/examples/valid/"
VALID_EXAMPLES
=(
"/constantPropagation/evaluation/"
"/propagation"
# "/evaluation"
)
VALID_EXAMPLE_LOG
=
"./log/const_eval.log"
>
$VALID_EXAMPLE_LOG
VALID_EXAMPLES_SRC_DIR
=
"./src/test/custom/valid/constantPropagation"
ASSEMBLY_OUTPUT_DIR
=
"./log/assembly/constantPropagation"
mkdir
log
mkdir
$ASSEMBLY_OUTPUT_DIR
TEST_DIR
=
"
$VALID_EXAMPLE_DIR$VALID_EXAMPLES
"
# counters to represent the total number of test files to be processed
TOTAL_COUNT
=
$(
find
"
$VALID_EXAMPLE
_DIR
${
VALID_EXAMPLES
[@]
}
"
-name
"*.wacc"
|
wc
-l
)
TOTAL_COUNT
=
$(
find
"
$
{
VALID_EXAMPLE
S
[@]/#/
${
VALID_EXAMPLES
_SRC_DIR
}
}
"
-name
"*.wacc"
|
wc
-l
)
COUNTER
=
0
for
folder
in
"
$VALID_EXAMPLE_DIR
${
VALID_EXAMPLES
[@]
}
"
;
do
for
file
in
$(
find
"
$folder
"
-name
"*.wacc"
)
;
do
for
folder
in
${
VALID_EXAMPLES
[@]
}
;
do
ASSEMBLY_OUTPUT_VALID_FOLDER
=
"
${
ASSEMBLY_OUTPUT_DIR
}${
folder
}
"
mkdir
$ASSEMBLY_OUTPUT_VALID_FOLDER
for
file
in
$(
find
"
${
VALID_EXAMPLES_SRC_DIR
}${
folder
}
"
-name
"*.wacc"
)
do
FILE_NAME
=
$(
basename
"
${
file
%.*
}
"
)
./compile
-o1
-t
$file
2>
$VALID_EXAMPLE_LOG
ret
=
$?
echo
"exit status: "
$ret
if
[
$ret
-ne
0
]
;
then
EXECUTABLE_FILE_NAME
=
"
${
ASSEMBLY_OUTPUT_VALID_FOLDER
}
/
${
FILE_NAME
}
"
echo
$file
echo
"status code incorrect: "
$ret
exit
1
./compile
-t
-o1
$file
>
"
${
EXECUTABLE_FILE_NAME
}
.log.txt"
if
diff
"
${
EXECUTABLE_FILE_NAME
}
.log.txt"
"
${
VALID_EXAMPLES_SRC_DIR
}${
folder
}
/
${
FILE_NAME
}
.log"
-I
scope
;
then
((
COUNTER +
=
1
))
fi
if
diff
"
$TEST_DIR
${
FILE_NAME
}
.log"
$VALID_EXAMPLE_LOG
>
temp
;
then
echo
$FILE_NAME
echo
"optimise differ from expected result: "
exit
1
fi
((
COUNTER +
=
1
))
echo
"
$COUNTER
/
$((
$TOTAL_COUNT
))
finished"
echo
""
echo
"
$COUNTER
/
$((
$TOTAL_COUNT
))
files have been executed"
done
echo
"========================================================================================"
...
...
scripts/extensionValidTest.sh
View file @
b42a3f3f
...
...
@@ -5,8 +5,8 @@ VALID_EXAMPLES=(
"/bitwiseOperation"
"/do-while"
"/for"
"/import"
# OK
"/jump"
# OK
"/import"
"/jump"
"/struct"
"/switch"
)
...
...
@@ -35,6 +35,8 @@ for folder in ${VALID_EXAMPLES[@]}; do
EXECUTABLE_OUTPUT_FILE
=
"
${
EXECUTE_OUTPUT_VALID_FOLDER
}
/
${
FILE_NAME
}
"
echo
$file
./compile
$file
2>
"
${
EXECUTABLE_FILE_NAME
}
.log.txt"
echo
"
${
EXECUTABLE_FILE_NAME
}
.s"
echo
"
${
FILE_NAME
}
.s"
mv
"
${
FILE_NAME
}
.s"
"
${
EXECUTABLE_FILE_NAME
}
.s"
arm-linux-gnueabi-gcc
-o
$EXECUTABLE_OUTPUT_FILE
-mcpu
=
arm1176jzf-s
-mtune
=
arm1176jzf-s
"
${
EXECUTABLE_FILE_NAME
}
.s"
>
"
${
EXECUTABLE_OUTPUT_FILE
}
.log.txt"
...
...
@@ -45,11 +47,11 @@ for folder in ${VALID_EXAMPLES[@]}; do
echo
"execution exit status"
$ret2
## altomatically generate output .log file
mv
"
${
EXECUTABLE_OUTPUT_FILE
}
.output.txt"
"
${
VALID_EXAMPLES_SRC_DIR
}${
folder
}
/
${
FILE_NAME
}
.log"
#
mv "${EXECUTABLE_OUTPUT_FILE}.output.txt" "${VALID_EXAMPLES_SRC_DIR}${folder}/${FILE_NAME}.log"
if
[
"
$ret1
"
-eq
0
]
&&
[
"
$ret2
"
-eq
0
]
;
then
## test if output is same as .log file
#
diff "${EXECUTABLE_OUTPUT_FILE}.output.txt" "${VALID_EXAMPLES_SRC_DIR}${folder}/${FILE_NAME}.log"
diff
"
${
EXECUTABLE_OUTPUT_FILE
}
.output.txt"
"
${
VALID_EXAMPLES_SRC_DIR
}${
folder
}
/
${
FILE_NAME
}
.log"
((
COUNTER +
=
1
))
fi
...
...
src/Compiler.java
View file @
b42a3f3f
...
...
@@ -64,13 +64,13 @@ public class Compiler {
int
optimise_cmd_index
=
cmd_ops
.
indexOf
(
"--optimise"
);
/* if not found optimise flag, no optimise */
if
(
optimise_cmd_index
==
0
)
{
if
(
optimise_cmd_index
!=
0
)
{
String
optimise_level
=
cmd_ops
.
get
(
optimise_cmd_index
+
1
);
switch
(
optimise_level
)
{
case
"0"
:
break
;
case
"1"
:
System
.
out
.
println
(
"optimising using const propagate"
);
NodeVisitor
<
Node
>
constPropOptimiser
=
new
ConstantPropagation
();
program
=
constPropOptimiser
.
visit
(
program
);
break
;
...
...
src/backend/ARMInstructionGenerator.java
View file @
b42a3f3f
...
...
@@ -83,6 +83,9 @@ public class ARMInstructionGenerator implements NodeVisitor<Void> {
no need to distinguish function and non function scope, as non function scope does not call return */
private
int
funcStackSize
;
/* used when a break/jump occure in a loop statment, accumulated on entering scope */
private
int
loopStackSize
;
/* used for mapping type with its print routine function */
private
final
Map
<
Type
,
RoutineInstruction
>
typeRoutineMap
=
Map
.
of
(
INT_BASIC_TYPE
,
PRINT_INT
,
...
...
@@ -683,16 +686,11 @@ public class ARMInstructionGenerator implements NodeVisitor<Void> {
/* 1 leave space for variables in stack */
int
stackSize
=
node
.
getStackSize
();
int
temp
=
stackSize
;
while
(
temp
>
0
)
{
int
realStackSize
=
temp
/
MAX_STACK_STEP
>=
1
?
MAX_STACK_STEP
:
temp
;
instructions
.
add
(
new
Sub
(
SP
,
SP
,
new
Operand2
(
realStackSize
)));
temp
=
temp
-
realStackSize
;
}
decStack
(
stackSize
);
/* accumulate function stack size, in case this scope is a function scope and contain return */
funcStackSize
+=
stackSize
;
loopStackSize
+=
stackSize
;
/* 2 visit statements
* set currentSymbolTable here, eliminate all other set symbol table in other statNode */
...
...
@@ -704,15 +702,10 @@ public class ARMInstructionGenerator implements NodeVisitor<Void> {
/* decrease function stack size, as from this point stack is freed by the scope, not by return */
funcStackSize
-=
stackSize
;
loopStackSize
-=
stackSize
;
/* 3 restore stack */
temp
=
stackSize
;
while
(
temp
>
0
)
{
int
realStackSize
=
temp
/
MAX_STACK_STEP
>=
1
?
MAX_STACK_STEP
:
temp
;
instructions
.
add
(
new
Add
(
SP
,
SP
,
new
Operand2
(
realStackSize
)));
temp
=
temp
-
realStackSize
;
}
incStack
(
stackSize
);
return
null
;
}
...
...
@@ -743,9 +736,16 @@ public class ARMInstructionGenerator implements NodeVisitor<Void> {
instructions
.
add
(
startLabel
);
/* record how much stack parent loop used */
int
prevLoopSize
=
loopStackSize
;
loopStackSize
=
0
;
/* 3 loop body */
visit
(
node
.
getBody
());
/* restore parent loop stack size */
loopStackSize
=
prevLoopSize
;
currBreakJumpToLabel
=
lastBreakJumpToLabel
;
currContinueJumpToLabel
=
lastContinueJumpToLabel
;
...
...
@@ -863,51 +863,51 @@ public class ARMInstructionGenerator implements NodeVisitor<Void> {
@Override
public
Void
visitForNode
(
ForNode
node
)
{
/* 1 translate the initiator of the for-loop */
currSymbolTable
=
node
.
getIncrement
().
getScope
();
int
stackSize
=
currSymbolTable
.
getSize
();
decStack
(
stackSize
);
visit
(
node
.
getInit
());
/* 2 create labels and translate for for-loop body */
Label
bodyLabel
=
branchLabelGenerator
.
getLabel
();
Label
condLabel
=
branchLabelGenerator
.
getLabel
();
Label
nextLabel
=
branchLabelGenerator
.
getLabel
();
Label
incrementLabel
=
branchLabelGenerator
.
getLabel
();
/* restore the last jump-to label after visiting the for-loop body */
Label
lastBreakJumpToLabel
=
currBreakJumpToLabel
;
Label
lastContinueJumpToLabel
=
currContinueJumpToLabel
;
currBreakJumpToLabel
=
nextLabel
;
currContinueJumpToLabel
=
cond
Label
;
currContinueJumpToLabel
=
increment
Label
;
instructions
.
add
(
new
B
(
NULL
,
condLabel
.
getName
()));
instructions
.
add
(
bodyLabel
);
currForLoopSymbolTable
=
node
.
getBody
().
getScope
();
/* record now much stack loop body have occupied */
int
prevLoopSize
=
loopStackSize
;
loopStackSize
=
0
;
visit
(
node
.
getBody
());
currBreakJumpToLabel
=
lastBreakJumpToLabel
;
currContinueJumpToLabel
=
lastContinueJumpToLabel
;
/* restore parent loop stack size */
loopStackSize
=
prevLoopSize
;
/* here we also need to append the for-loop in crement at the end */
/* here we also need to append the for-loop increment at the end */
instructions
.
add
(
incrementLabel
);
visit
(
node
.
getIncrement
());
currBreakJumpToLabel
=
lastBreakJumpToLabel
;
currContinueJumpToLabel
=
lastContinueJumpToLabel
;
/* 3 add label for condition checking */
instructions
.
add
(
condLabel
);
currSymbolTable
=
node
.
getBody
().
getScope
();
/* TODO: better code quality here */
int
stackSize
=
currSymbolTable
.
getSize
();
int
temp
=
stackSize
;
while
(
temp
>
0
)
{
int
realStackSize
=
temp
/
MAX_STACK_STEP
>=
1
?
MAX_STACK_STEP
:
temp
;
instructions
.
add
(
new
Sub
(
SP
,
SP
,
new
Operand2
(
realStackSize
)));
temp
=
temp
-
realStackSize
;
}
currSymbolTable
=
node
.
getIncrement
().
getScope
();
visit
(
node
.
getCond
());
temp
=
stackSize
;
while
(
temp
>
0
)
{
int
realStackSize
=
temp
/
MAX_STACK_STEP
>=
1
?
MAX_STACK_STEP
:
temp
;
instructions
.
add
(
new
Add
(
SP
,
SP
,
new
Operand2
(
realStackSize
)));
temp
=
temp
-
realStackSize
;
}
currSymbolTable
=
currSymbolTable
.
getParentSymbolTable
();
instructions
.
add
(
new
Cmp
(
armRegAllocator
.
curr
(),
new
Operand2
(
TRUE
)));
armRegAllocator
.
free
();
...
...
@@ -917,32 +917,24 @@ public class ARMInstructionGenerator implements NodeVisitor<Void> {
/* 5 add the label for the following instructions after for-loop */
instructions
.
add
(
nextLabel
);
/* loop varient's stack clearing should be after next label,
so that BREAK can add back stack used by varients */
incStack
(
stackSize
);
return
null
;
}
@Override
public
Void
visitJumpNode
(
JumpNode
node
)
{
Instruction
addStack
=
n
ull
;
List
<
Instruction
>
addStack
=
n
ew
ArrayList
<>()
;
/* this snippet is to deal with for-loop stack difference */
if
(
currForLoopSymbolTable
!=
null
&&
!
node
.
getJumpContext
().
equals
(
JumpContext
.
SWITCH
))
{
int
stackSize
=
currForLoopSymbolTable
.
getSize
();
int
temp
=
stackSize
;
while
(
temp
>
0
)
{
int
realStackSize
=
temp
/
MAX_STACK_STEP
>=
1
?
MAX_STACK_STEP
:
temp
;
addStack
=
new
Add
(
SP
,
SP
,
new
Operand2
(
realStackSize
));
temp
=
temp
-
realStackSize
;
}
if
(!
node
.
getJumpType
().
equals
(
JumpType
.
BREAK
)
||
!
node
.
getJumpContext
().
equals
(
JumpContext
.
SWITCH
))
{
incStack
(
loopStackSize
);
}
if
(
node
.
getJumpType
().
equals
(
JumpType
.
BREAK
))
{
if
(
addStack
!=
null
)
instructions
.
add
(
addStack
);
instructions
.
add
(
new
B
(
NULL
,
currBreakJumpToLabel
.
getName
()));
}
else
if
(
node
.
getJumpType
().
equals
(
JumpType
.
CONTINUE
))
{
/* this snippet is to deal with the for-loop increment */
StatNode
increment
=
node
.
getForIncrement
();
if
(
increment
!=
null
)
visit
(
increment
);
if
(
addStack
!=
null
)
instructions
.
add
(
addStack
);
instructions
.
add
(
new
B
(
NULL
,
currContinueJumpToLabel
.
getName
()));
}
...
...
@@ -988,4 +980,22 @@ public class ARMInstructionGenerator implements NodeVisitor<Void> {
return
null
;
}
private
void
incStack
(
int
stackSize
)
{
while
(
stackSize
>
0
)
{
int
realStackSize
=
stackSize
/
MAX_STACK_STEP
>=
1
?
MAX_STACK_STEP
:
stackSize
;
instructions
.
add
(
new
Add
(
SP
,
SP
,
new
Operand2
(
realStackSize
)));
stackSize
=
stackSize
-
realStackSize
;
}
}
private
void
decStack
(
int
stackSize
)
{
while
(
stackSize
>
0
)
{
int
realStackSize
=
stackSize
/
MAX_STACK_STEP
>=
1
?
MAX_STACK_STEP
:
stackSize
;
instructions
.
add
(
new
Sub
(
SP
,
SP
,
new
Operand2
(
realStackSize
)));
stackSize
=
stackSize
-
realStackSize
;
}
}
}
src/frontend/ASTPrinter.java
View file @
b42a3f3f
...
...
@@ -328,12 +328,13 @@ public class ASTPrinter implements NodeVisitor<Void> {
/* body */
leadingSpace
+=
INDENT_SIZE
;
visit
(
node
.
getBody
());
leadingSpace
-=
INDENT_SIZE
;
appendLeadingSpace
();
System
.
out
.
print
(
"while "
);
visit
(
node
.
getCond
());
System
.
out
.
println
(
" :"
);
leadingSpace
-=
INDENT_SIZE
;
}
else
{
System
.
out
.
print
(
"while "
);
visit
(
node
.
getCond
());
...
...
@@ -384,10 +385,16 @@ public class ASTPrinter implements NodeVisitor<Void> {
/* for 3 expressions : */
appendLeadingSpace
();
System
.
out
.
print
(
"for "
);
leadingSpace
+=
INDENT_SIZE
;
visit
(
node
.
getInit
());
appendLeadingSpace
();
visit
(
node
.
getCond
());
visit
(
node
.
getIncrement
());
System
.
out
.
println
(
" :"
);
leadingSpace
-=
INDENT_SIZE
;
appendLeadingSpace
();
System
.
out
.
println
(
":"
);
/* body */
leadingSpace
+=
INDENT_SIZE
;
...
...
@@ -406,15 +413,18 @@ public class ASTPrinter implements NodeVisitor<Void> {
public
Void
visitSwitchNode
(
SwitchNode
node
)
{
/* switch statement */
appendLeadingSpace
();
System
.
out
.
println
(
"switch "
);
System
.
out
.
println
(
node
.
getExpr
());
System
.
out
.
print
(
"switch "
);
visit
(
node
.
getExpr
());
System
.
out
.
println
();
/* switch body */
leadingSpace
+=
INDENT_SIZE
;
for
(
CaseStat
c
:
node
.
getCases
())
{
System
.
out
.
println
(
"case "
);
appendLeadingSpace
();
System
.
out
.
print
(
"case "
);
visit
(
c
.
getExpr
());
System
.
out
.
println
();
/* case body */
leadingSpace
+=
INDENT_SIZE
;
...
...
@@ -422,9 +432,12 @@ public class ASTPrinter implements NodeVisitor<Void> {
leadingSpace
-=
INDENT_SIZE
;
}
appendLeadingSpace
();
System
.
out
.
println
(
"default"
);
leadingSpace
+=
INDENT_SIZE
;
visit
(
node
.
getDefault
());
leadingSpace
-=
INDENT_SIZE
;
leadingSpace
-=
2
*
INDENT_SIZE
;
return
null
;
}
...
...
src/frontend/SemanticChecker.java
View file @
b42a3f3f
...
...
@@ -11,11 +11,7 @@ import java.io.File;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.*
;
import
frontend.node.FuncNode
;
import
frontend.node.Node
;
...
...
@@ -30,7 +26,6 @@ import frontend.node.expr.BinopNode.Binop;
import
frontend.node.expr.UnopNode.Unop
;
import
frontend.type.*
;
import
java.util.Set
;
import
org.antlr.v4.runtime.tree.TerminalNode
;
import
org.antlr.v4.runtime.CharStream
;
...
...
@@ -70,10 +65,13 @@ public class SemanticChecker extends WACCParserBaseVisitor<Node> {
private
boolean
isMainFunction
;
/* used in determining whether branching statement is legal, i.e. break/continue is within a loop/switch */
private
boolean
isBreakAllowed
;
private
boolean
isContinueAllowed
;
private
boolean
isJumpRepeated
;
private
JumpContext
jumpContext
;
private
Stack
<
Boolean
>
isBreakAllowed
;
private
Stack
<
Boolean
>
isContinueAllowed
;
private
Stack
<
Boolean
>
isJumpRepeated
;
private
Stack
<
JumpContext
>
jumpContext
;
/* record the for-loop incrementer so that break and continue know what to do before jumping */
private
Stack
<
StatNode
>
currForLoopIncrementBreak
;
private
Stack
<
StatNode
>
currForLoopIncrementContinue
;
/* used only in function declare step, to check function has the correct return type */
private
Type
expectedFunctionReturn
;
...
...
@@ -81,15 +79,11 @@ public class SemanticChecker extends WACCParserBaseVisitor<Node> {
/* record whether a skipable semantic error is found in visiting to support checking of multiple errors */
private
boolean
semanticError
;
/* record the for-loop incrementer so that break and continue know what to do before jumping */
private
StatNode
currForLoopIncrementBreak
;
private
StatNode
currForLoopIncrementContinue
;
/* record which file have already been included, IN the current import chain */
private
Set
<
String
>
libraryCollection
;
/* record all files that have been imported */
private
Set
<
String
>
allImportCollection
=
new
HashSet
<>();
private
static
Set
<
String
>
allImportCollection
=
new
HashSet
<>();
/* for function overload */
private
Set
<
String
>
overloadFuncNames
=
new
HashSet
<>();
...
...
@@ -101,13 +95,21 @@ public class SemanticChecker extends WACCParserBaseVisitor<Node> {
globalStructTable
=
new
HashMap
<>();
globalFuncTable
=
new
HashMap
<>();
isMainFunction
=
false
;
isBreakAllowed
=
false
;
isContinueAllowed
=
false
;
jumpContext
=
null
;
isJumpRepeated
=
false
;
isBreakAllowed
=
new
Stack
<>();
isBreakAllowed
.
push
(
false
);
isContinueAllowed
=
new
Stack
<>();
isContinueAllowed
.
push
(
false
);
jumpContext
=
new
Stack
<>();
isJumpRepeated
=
new
Stack
<>();
isJumpRepeated
.
push
(
false
);
expectedFunctionReturn
=
null
;
currForLoopIncrementBreak
=
n
ull
;
currForLoopIncrementContinue
=
n
ull
;
currForLoopIncrementBreak
=
n
ew
Stack
<>()
;
currForLoopIncrementContinue
=
n
ew
Stack
<>()
;
this
.
libraryCollection
=
libraryCollection
;
}
...
...
@@ -376,11 +378,11 @@ public class SemanticChecker extends WACCParserBaseVisitor<Node> {
currSymbolTable
=
currSymbolTable
.
getParentSymbolTable
();
if
(
functionBody
instanceof
ScopeNode
)
{
((
ScopeNode
)
functionBody
).
set
FuncBody
();
((
ScopeNode
)
functionBody
).
set
AvoidSubStack
();
return
functionBody
;
}
ScopeNode
enclosedBody
=
new
ScopeNode
(
functionBody
);
enclosedBody
.
set
FuncBody
();
enclosedBody
.
set
AvoidSubStack
();
return
enclosedBody
;
}
...
...
@@ -412,19 +414,26 @@ public class SemanticChecker extends WACCParserBaseVisitor<Node> {
semanticError
|=
typeCheck
(
ctx
.
expr
(),
BOOL_BASIC_TYPE
,
conditionType
);
/* both branch are permitted to have/not have jump */
boolean
permitJump
=
isJumpRepeated
;
boolean
permitJump
=
isJumpRepeated
.
peek
()
;
/* create the StatNode for the if body and gegerate new child scope */
currSymbolTable
=
new
SymbolTable
(
currSymbolTable
);
StatNode
ifBody
=
visit
(
ctx
.
stat
(
0
)).
asStatNode
();
currSymbolTable
=
currSymbolTable
.
getParentSymbolTable
();
isJumpRepeated
=
permitJump
;
/* restore permit/not permit jump */
isJumpRepeated
.
pop
();
isJumpRepeated
.
push
(
permitJump
);
/* create the StatNode for the else body and generate new child scope */
currSymbolTable
=
new
SymbolTable
(
currSymbolTable
);
StatNode
elseBody
=
visit
(
ctx
.
stat
(
1
)).
asStatNode
();
currSymbolTable
=
currSymbolTable
.
getParentSymbolTable
();
/* restore permit/not permit jump */
isJumpRepeated
.
pop
();
isJumpRepeated
.
push
(
permitJump
);
StatNode
node
=
new
IfNode
(
condition
,
ifBody
instanceof
ScopeNode
?
ifBody
:
...
...
@@ -448,16 +457,20 @@ public class SemanticChecker extends WACCParserBaseVisitor<Node> {
/* get the StatNode of the execution body of while loop */
currSymbolTable
=
new
SymbolTable
(
currSymbolTable
);
boolean
isNestedBreak
=
isBreakAllowed
;
boolean
isNestedContinue
=
isContinueAllowed
;
isBreakAllowed
=
isContinueAllowed
=
true
;
jumpContext
=
JumpContext
.
WHILE
;
isJumpRepeated
=
false
;
/* set context for WHILE */
isJumpRepeated
.
push
(
false
);
isBreakAllowed
.
push
(
true
);
isContinueAllowed
.
push
(
true
);
jumpContext
.
push
(
JumpContext
.
WHILE
);
StatNode
body
=
visit
(
ctx
.
stat
()).
asStatNode
();
currSymbolTable
=
currSymbolTable
.
getParentSymbolTable
();
if
(!
isNestedBreak
)
isBreakAllowed
=
false
;
if
(!
isNestedContinue
)
isContinueAllowed
=
false
;
/* reset context to parent scope */
isJumpRepeated
.
pop
();
isBreakAllowed
.
pop
();
isContinueAllowed
.
pop
();
jumpContext
.
pop
();
StatNode
node
=
(
body
instanceof
ScopeNode
)
?
new
WhileNode
(
condition
,
body
)
:
...
...
@@ -476,9 +489,21 @@ public class SemanticChecker extends WACCParserBaseVisitor<Node> {
/* get the StatNode of the execution body of while loop */
currSymbolTable
=
new
SymbolTable
(
currSymbolTable
);
isBreakAllowed
=
isContinueAllowed
=
true
;
/* set contexts for DOWHILE */
isJumpRepeated
.
push
(
false
);
isBreakAllowed
.
push
(
true
);
isContinueAllowed
.
push
(
true
);
jumpContext
.
push
(
JumpContext
.
WHILE
);
StatNode
body
=
visit
(
ctx
.
stat
()).
asStatNode
();
isBreakAllowed
=
isContinueAllowed
=
false
;
/* reset context to parent scope */
isJumpRepeated
.
pop
();
isBreakAllowed
.
pop
();
isContinueAllowed
.
pop
();
jumpContext
.
pop
();
currSymbolTable
=
currSymbolTable
.
getParentSymbolTable
();
StatNode
node
=
(
body
instanceof
ScopeNode
)
?
...
...
@@ -496,31 +521,38 @@ public class SemanticChecker extends WACCParserBaseVisitor<Node> {
/* visit the initiator */
StatNode
init
=
visit
(
ctx
.
for_stat
(
0
)).
asStatNode
();
/* isNestedBreak and isNestedContinue is used for nested/mixed loops/switch statements */
boolean
isNestedBreak
=
isBreakAllowed
;
boolean
isNestedContinue
=
isContinueAllowed
;
ExprNode
cond
=
visit
(
ctx
.
expr
()).
asExprNode
();
StatNode
increment
=
visit
(
ctx
.
for_stat
(
1
)).
asStatNode
();
/* mark the point where break and continue are allowed to appear */
isBreakAllowed
=
isContinueAllowed
=
true
;
/* record the for-loop increment so that when `continue` appear, it still processes the increment in the assembly */