Translation notice
This page was translated with machine translation and may contain inaccuracies. If you can help improve it, please open an issue or submit a pull request.
Use data pack to make a compiler or interpreter: Take the C language subset C-Minus as an example
4. Syntax analysis (Parse), semantic analysis and intermediate code generation
4.4 Construction of expression evaluation part
4.4.1 Preparation
Similar to the lexical analyzer, we will also use predicate here to simplify some type distinctions that require complex execute judgments.
predicate c-:parse/type-specifier(Type qualifier, for C-Minus onlyintandvoid。)
{"condition":"any_of","terms":[
{"condition":"entity_scores","entity":"this","scores":{"c-token":-4}},
{"condition":"entity_scores","entity":"this","scores":{"c-token":-5}}]
}predicate c-:parse/addop(Addition operator, including+and`
- `)
{"condition":"any_of","terms":[
{"condition":"entity_scores","entity":"this","scores":{"c-token":43}},
{"condition":"entity_scores","entity":"this","scores":{"c-token":45}}]
}predicate c-:parse/mulop(Multiplication operator, including*,/and%)
{"condition":"any_of","terms":[
{"condition":"entity_scores","entity":"this","scores":{"c-token":42}},
{"condition":"entity_scores","entity":"this","scores":{"c-token":47}},
{"condition":"entity_scores","entity":"this","scores":{"c-token":37}}]
}predicate c-:parse/relop(comparison operator, including==,<=,>=,!=,>and<)
{"condition":"any_of","terms":[
{"condition":"entity_scores","entity":"this","scores":{"c-token":60}},
{"condition":"entity_scores","entity":"this","scores":{"c-token":62}},
{"condition":"entity_scores","entity":"this","scores":{"c-token":{"min":75,"max":78}}}]
}predicate c-:parse/movop(Assignment operator, including=,+=,-=,*=,/=and%=)
{"condition":"any_of","terms":[
{"condition":"entity_scores","entity":"this","scores":{"c-token":61}},
{"condition":"entity_scores","entity":"this","scores":{"c-token":{"min":70,"max":74}}}]
}4.4.2 Start
Since in some cases the first lexeme of an expression has been read before it can be determined that the expression will be parsed using the expression method, we use a method similar to the lexical analysis part here, that is, the "start state" of expression recognition is the state in which the first lexeme has been recognized and returned.
At the same time, since subexpressions can be embedded in expressions through parentheses and function calls, we complete the overall initialization work in another function and use the stack to manage the relationship between the main expression and subexpressions. The recognition of sub-expressions at each level will start atnow-expressionA list is added after the list, and after the recognition is completed, it will be sorted to the upper level list as the last element.
function c-:parse/expression/start
data modify storage c-: now-expression set value []
scoreboard players set #tmpvar-count c- 0
function c-:parse/expression/function c-:parse/expression/
data modify storage c-: now-expression append value []
execute if score @s[tag=c-exp-constant] c-token = #name c-token run return run function c-:terminate {msg:"SyntaxError: initializer element is not constant"}
execute if score @s c-token = #name c-token run return run function c-:parse/expression/name
execute if score @s c-token = #number c-token run return run function c-:parse/expression/number
execute if score @s c-token = #( c-chr run return run function c-:parse/expression/bracket
execute if predicate c-:parse/addop run return run function c-:parse/expression/unary
function c-:terminate {msg:"SyntaxError: expected expression before '%3$s' token"}4.4.3 Variables and Numeric Nodes
Since we usually need to see the next operator on a variable to decide whether it is reduced, no reduction is attempted on a variable or number when it is read in. More informally, we will always "let operators find and combine variables". However, there are two things that need to be done here, namely, determine the scope of the read variable name and append the scope offset value information; register the read number to the constant scoreboard.
function c-:parse/expression/number
# -- THIS --
data modify storage c-: now-expression[-1] append value {_:{__:-100}}
execute store result storage c-: now-expression[-1][-1]._._ int 1 run scoreboard players get @s c-
function c-:parse/constant-register with storage c-: now-expression[-1][-1]._
# -- NEXT --
function c-:lexical-analysis/node/
execute if predicate c-:parse/mulop run return run function c-:parse/expression/mulop
execute if predicate c-:parse/addop run return run function c-:parse/expression/addop
execute if predicate c-:parse/relop run return run function c-:parse/expression/relop
# -- ERROR --
execute if predicate c-:parse/movop run return run function c-:terminate {msg:"SyntaxError: lvalue required as left operand of assignment"}
# -- END --
return run function c-:parse/expression/endfunction c-:parse/constant-register
$scoreboard players set #$(_) c-data.-100 $(_)function c-:parse/expression/name
# -- THIS --
function c-:parse/find-name/
data modify storage c-: now-expression[-1] append value {}
data modify storage c-: now-expression[-1][-1]._ set from storage c-: extract
# -- NEXT --
function c-:lexical-analysis/node/
execute if predicate c-:parse/mulop run return run function c-:parse/expression/mulop
execute if predicate c-:parse/addop run return run function c-:parse/expression/addop
execute if predicate c-:parse/relop run return run function c-:parse/expression/relop
execute if predicate c-:parse/movop run return run function c-:parse/expression/mov
execute if score @s c-token = #( c-chr run return run function c-:parse/expression/call/start
# -- ERROR --
# -- END --
return run function c-:parse/expression/endWe will use the following set of functions to determine the scope of variables. It should be noted that the function name belongs to a global variable, and its location will be used to store the return value of the function. function c-:parse/find-name/
execute store result score #visit-chain-len c- run data get storage c-: now-variable
scoreboard players set #var-offset c- 0
execute if score #visit-chain-len c- matches 1.. run function c-:parse/find-name/_function c-:parse/find-name/_
# Loop: Layered Local scope
scoreboard players remove #visit-chain-len c- 1
execute store result storage c-: extract.__ int 1 run scoreboard players get #visit-chain-len c-
execute store result score #__got c- run function c-:parse/find-name/__ with storage c-: extract
execute if score #__got c- matches 1 run return run execute store result storage c-: extract.__ int 1 run scoreboard players get #var-offset c-
# Fallback: global scope
scoreboard players add #var-offset c- 1
execute if score #visit-chain-len c- matches 1.. run return run function c-:parse/find-name/_
execute store result score #__got c- run function c-:parse/find-name/- with storage c-: extract
execute if score #__got c- matches 1 run return run data modify storage c-: extract.__ set value -1
# Error
function c-:terminate {msg:"NameError: name '%3$s' is not defined (first use in this function)"}function c-:parse/find-name/__
$return run execute if data storage c-: now-variable[$(__)][{name:"$(_)"}]function c-:parse/find-name/-
$return run execute if data storage c-: variable[{name:"$(_)"}]4.4.4 Operator Node
Operator nodes will try to perform all possible feasible reduction operations (except unary operators, we will treat unary positive and negative operators directly as addition and subtraction with operands of 0). For example, multiplication nodes will try to perform multiplicative reduction, while addition nodes will try to perform multiplication and additive reduction. Since both addition and multiplication are left associative operations, each reduction attempt is only performed once.
function c-:parse/expression/unary
# -- THIS --
data modify storage c-: now-expression[-1] append value {_:{_:0,__:-100}}
execute store result storage c-: now-expression[-1][-1]._.v byte 1 run scoreboard players get @s c-token
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s[tag=c-exp-constant] c-token = #name c-token run return run function c-:terminate {msg:"SyntaxError: initializer element is not constant"}
execute if score @s c-token = #name c-token run return run function c-:parse/expression/name
execute if score @s c-token = #number c-token run return run function c-:parse/expression/number
execute if score @s c-token = #( c-chr run return run function c-:parse/expression/bracket
# -- ERROR --
function c-:terminate {msg:"SyntaxError: expected expression before '%3$s' token"}
# -- END --function c-:parse/expression/mulop
# -- THIS --
function c-:parse/expression/reduction/mulop/
execute store result storage c-: now-expression[-1][-1]._.v byte 1 run scoreboard players get @s c-token
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s[tag=c-exp-constant] c-token = #name c-token run return run function c-:terminate {msg:"SyntaxError: initializer element is not constant"}
execute if score @s c-token = #name c-token run return run function c-:parse/expression/name
execute if score @s c-token = #number c-token run return run function c-:parse/expression/number
execute if predicate c-:parse/addop run return run function c-:parse/expression/unary
execute if score @s c-token = #( c-chr run return run function c-:parse/expression/bracket
# -- ERROR --
function c-:terminate {msg:"SyntaxError: expected expression before '%3$s' token"}
# -- END --function c-:parse/expression/addop
# -- THIS --
function c-:parse/expression/reduction/mulop/
function c-:parse/expression/reduction/addop/
execute store result storage c-: now-expression[-1][-1]._.v byte 1 run scoreboard players get @s c-token
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s[tag=c-exp-constant] c-token = #name c-token run return run function c-:terminate {msg:"SyntaxError: initializer element is not constant"}
execute if score @s c-token = #name c-token run return run function c-:parse/expression/name
execute if score @s c-token = #number c-token run return run function c-:parse/expression/number
execute if predicate c-:parse/addop run return run function c-:parse/expression/unary
execute if score @s c-token = #( c-chr run return run function c-:parse/expression/bracket
# -- ERROR --
function c-:terminate {msg:"SyntaxError: expected expression before '%3$s' token"}
# -- END --function c-:parse/expression/relop
# -- THIS --
function c-:parse/expression/reduction/mulop/
function c-:parse/expression/reduction/addop/
function c-:parse/expression/reduction/relop/
execute store result storage c-: now-expression[-1][-1]._.v byte 1 run scoreboard players get @s c-token
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s[tag=c-exp-constant] c-token = #name c-token run return run function c-:terminate {msg:"SyntaxError: initializer element is not constant"}
execute if score @s c-token = #name c-token run return run function c-:parse/expression/name
execute if score @s c-token = #number c-token run return run function c-:parse/expression/number
execute if predicate c-:parse/addop run return run function c-:parse/expression/unary
execute if score @s c-token = #( c-chr run return run function c-:parse/expression/bracket
# -- ERROR --
function c-:terminate {msg:"SyntaxError: expected expression before '%3$s' token"}
# -- END --The assignment statement is special. Since the assignment is a right associative operation, the reduction can only start after the entire statement is completed, so it can only be registered when the equal sign is read.
function c-:parse/expression/mov
# -- THIS --
execute store result storage c-: now-expression[-1][-1]._.v byte 1 run scoreboard players get @s c-token
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s[tag=c-exp-constant] c-token = #name c-token run return run function c-:terminate {msg:"SyntaxError: initializer element is not constant"}
execute if score @s c-token = #name c-token run return run function c-:parse/expression/name
execute if score @s c-token = #number c-token run return run function c-:parse/expression/number
execute if predicate c-:parse/addop run return run function c-:parse/expression/unary
execute if score @s c-token = #( c-chr run return run function c-:parse/expression/bracket
# -- ERROR --
function c-:terminate {msg:"SyntaxError: expected expression before '%3$s' token"}
# -- END --4.4.5 End node
Reading characters other than operators such as commas, parentheses, and semicolons will trigger the end of the expression in this layer (the exception is the left parenthesis, whose behavior is to start a new expression layer). At the end, addition and multiplication reduction will be attempted again, and finally assignment statement reduction will be performed. Due to the right associativity of the assignment statement, the reduction operation of the assignment statement here will be performed in a loop. function c-:parse/expression/end
function c-:parse/expression/reduction/mulop/
function c-:parse/expression/reduction/addop/
function c-:parse/expression/reduction/relop/
function c-:parse/expression/reduction/mov/4.4.6 Subexpression node
A subexpression node begins with the parentheses that are not appended to the variable name and ends with the right parenthesis. During the subexpression recognition process, it will be on the stacknow-expressionA new item is appended to the item, and after the recognition is completed, the final element of the item will be appended to the end of the previous layer as one of the elements and continue to participate in the operation of the previous layer.
Notice
The C language has a less common syntax that allows multiple expressions to be separated by commas, and only the value of the last expression will be returned. This grammatical situation is considered here.
function c-:parse/expression/bracket
# -- THIS --
function c-:lexical-analysis/node/
function c-:parse/expression/
execute if score @s c-token = #, c-chr run return run function c-:parse/expression/bracket_sep
execute unless score @s c-token = #) c-chr run return run function c-:terminate {msg:"SyntaxError: expected ')' before '%3$s' token"}
data modify storage c-: now-expression[-2] append from storage c-: now-expression[-1][0]
data remove storage c-: now-expression[-1]
# -- NEXT --
function c-:lexical-analysis/node/
execute if predicate c-:parse/mulop run return run function c-:parse/expression/mulop
execute if predicate c-:parse/addop run return run function c-:parse/expression/addop
execute if predicate c-:parse/relop run return run function c-:parse/expression/relop
# -- ERROR --
execute if predicate c-:parse/movop run return run function c-:terminate {msg:"SyntaxError: lvalue required as left operand of assignment"}
# -- END --
return run function c-:parse/expression/endfunction c-:parse/expression/bracket_sep
data remove storage c-: now-expression[-1]
return run function c-:parse/expression/bracket4.4.7 function call node
The function call node starts with the parentheses appended to the variable name and ends with the closing parenthesis. Each of these parameters will be a subexpression.
function c-:parse/expression/call/start
# -- THIS --
function c-:parse/expression/call/start_ with storage c-: now-expression[-1][-1]._
function c-:parse/expression/reduction/call/start
# -- NEXT --
function c-:lexical-analysis/node/
execute unless score @s c-token = #) c-chr run return run function c-:parse/expression/call/expr
return run function c-:parse/expression/call/end
# -- ERROR --
# -- END --function c-:parse/expression/call/start_
$execute unless data storage c-: variable[{name:"$(_)"}] run return run function c-:terminate {msg:"implicit declaration of function '$(_)'"}
$data modify storage c-: now-expression[-1][-1]._.arg set from storage c-: variable[{name:"$(_)"}].arg
$data modify storage c-: now-expression[-1][-1]._.__ set from storage c-: variable[{name:"$(_)"}].typefunction c-:parse/expression/call/expr
# -- THIS --
function c-:parse/expression/
execute if data storage c-: now-expression[-2][-1]._.arg run function c-:parse/expression/reduction/call/arg
data remove storage c-: now-expression[-1]
# -- NEXT --
execute if score @s c-token = #, c-chr run return run function c-:parse/expression/call/sep
execute if score @s c-token = #) c-chr run return run function c-:parse/expression/call/end
# -- ERROR --
return run function c-:terminate {msg:"SyntaxError: expected ')' before '%3$s' token"}function c-:parse/expression/call/sep
function c-:lexical-analysis/node/
return run function c-:parse/expression/call/exprfunction c-:parse/expression/call/end
# -- THIS --
function c-:parse/expression/reduction/call/end
# -- NEXT --
function c-:lexical-analysis/node/
execute if predicate c-:parse/mulop run return run function c-:parse/expression/mulop
execute if predicate c-:parse/addop run return run function c-:parse/expression/addop
execute if predicate c-:parse/relop run return run function c-:parse/expression/relop
# -- ERROR --
execute if predicate c-:parse/movop run return run function c-:terminate {msg:"SyntaxError: lvalue required as left operand of assignment"}
# -- END --
return run function c-:parse/expression/end4.4.8 Reduction part
4.4.8.1 Additive reduction
We will divide the addition part into the following four categories:
- The former item is a temporary variable. At this time, we directly add and subtract the latter item to the previous item, and the result item is the previous item.
- The preceding and following terms are both constants. At this time, we directly perform constant calculations, and the result term is the result of the operation.
- One of the before and after items is of type
void(from void type function), error reported. - For the rest, create a new temporary variable equal to the previous item, add or subtract the latter item to the temporary variable, and the result item is the temporary variable.
function c-:parse/expression/reduction/addop/
data modify storage c-: now-codeline set value {}
execute if data storage c-: now-expression[-1][-2]._{v:43b} run data modify storage c-: now-codeline.v set value add
execute if data storage c-: now-expression[-1][-2]._{v:45b} run data modify storage c-: now-codeline.v set value sub
execute if data storage c-: now-codeline.v run return run function c-:parse/expression/reduction/addop/_function c-:parse/expression/reduction/addop/_
execute if data storage c-: now-expression[-1][-2]._{__:-2} run return run function c-:parse/expression/reduction/addop/_1
execute if data storage c-: now-expression[-1][-2]._{__:-100} if data storage c-: now-expression[-1][-1]._{__:-100} run return run function c-:parse/expression/reduction/addop/_2
execute unless data storage c-: now-expression[-1][-2]._{__:-2147483648} unless data storage c-: now-expression[-1][-1]._{__:-2147483648} run return run function c-:parse/expression/reduction/addop/_3
return run function c-:terminate {msg:"TypeError: void value not ignored as it ought to be"}function c-:parse/expression/reduction/addop/_1
data modify storage c-: now-codeline.s_ set value -2
data modify storage c-: now-codeline.s set from storage c-: now-expression[-1][-2]._._
data modify storage c-: now-codeline.o set from storage c-: now-expression[-1][-1]._._
data modify storage c-: now-codeline.o_ set from storage c-: now-expression[-1][-1]._.__
data modify storage c-: now-function.code append from storage c-: now-codeline
data modify storage c-: now-expression[-1][-1]._ set from storage c-: now-expression[-1][-2]._
data remove storage c-: now-expression[-1][-2]function c-:parse/expression/reduction/addop/_2
execute store result score #tmp_number0 c- run data get storage c-: now-expression[-1][-2]._._
execute store result score #tmp_number1 c- run data get storage c-: now-expression[-1][-1]._._
execute if data storage c-: now-expression[-1][-2]._{v:43b} run scoreboard players operation #tmp_number0 c- += #tmp_number1 c-
execute if data storage c-: now-expression[-1][-2]._{v:45b} run scoreboard players operation #tmp_number0 c- -= #tmp_number1 c-
execute store result storage c-: now-expression[-1][-1]._._ int 1 run scoreboard players get #tmp_number0 c-
function c-:parse/constant-register with storage c-: now-expression[-1][-1]._
data remove storage c-: now-expression[-1][-2]function c-:parse/expression/reduction/addop/_3
data modify storage c-: now-function.code append value {s_:-2,v:mov}
execute store result storage c-: now-function.code[-1].s int 1 run scoreboard players add #tmpvar-count c- 1
data modify storage c-: now-function.code[-1].o set from storage c-: now-expression[-1][-2]._._
data modify storage c-: now-function.code[-1].o_ set from storage c-: now-expression[-1][-2]._.__
data modify storage c-: now-codeline.s_ set value -2
data modify storage c-: now-codeline.s set from storage c-: now-function.code[-1].s
data modify storage c-: now-codeline.o set from storage c-: now-expression[-1][-1]._._
data modify storage c-: now-codeline.o_ set from storage c-: now-expression[-1][-1]._.__
data modify storage c-: now-function.code append from storage c-: now-codeline
data modify storage c-: now-expression[-1][-1]._._ set from storage c-: now-codeline.s
data modify storage c-: now-expression[-1][-1]._.__ set value -2
data remove storage c-: now-expression[-1][-2]4.4.8.2 Multiplicative reduction
The basic case of multiplicative reduction is exactly the same as that of addition.
function c-:parse/expression/reduction/mulop/
data modify storage c-: now-codeline set value {}
execute if data storage c-: now-expression[-1][-2]._{v:42b} run data modify storage c-: now-codeline.v set value mul
execute if data storage c-: now-expression[-1][-2]._{v:47b} run data modify storage c-: now-codeline.v set value div
execute if data storage c-: now-expression[-1][-2]._{v:37b} run data modify storage c-: now-codeline.v set value mod
execute if data storage c-: now-codeline.v run return run function c-:parse/expression/reduction/mulop/_function c-:parse/expression/reduction/mulop/_
execute if data storage c-: now-expression[-1][-2]._{__:-2} run return run function c-:parse/expression/reduction/mulop/_1
execute if data storage c-: now-expression[-1][-2]._{__:-100} if data storage c-: now-expression[-1][-1]._{__:-100} run return run function c-:parse/expression/reduction/mulop/_2
execute unless data storage c-: now-expression[-1][-2]._{__:-2147483648} unless data storage c-: now-expression[-1][-1]._{__:-2147483648} run return run function c-:parse/expression/reduction/mulop/_3
return run function c-:terminate {msg:"TypeError: void value not ignored as it ought to be"}function c-:parse/expression/reduction/mulop/_1
data modify storage c-: now-codeline.s_ set value -2
data modify storage c-: now-codeline.s set from storage c-: now-expression[-1][-2]._._
data modify storage c-: now-codeline.o set from storage c-: now-expression[-1][-1]._._
data modify storage c-: now-codeline.o_ set from storage c-: now-expression[-1][-1]._.__
data modify storage c-: now-function.code append from storage c-: now-codeline
data modify storage c-: now-expression[-1][-1]._ set from storage c-: now-expression[-1][-2]._
data remove storage c-: now-expression[-1][-2]function c-:parse/expression/reduction/mulop/_2
execute store result score #tmp_number0 c- run data get storage c-: now-expression[-1][-2]._._
execute store result score #tmp_number1 c- run data get storage c-: now-expression[-1][-1]._._
execute if data storage c-: now-expression[-1][-2]._{v:42b} run scoreboard players operation #tmp_number0 c- *= #tmp_number1 c-
execute if data storage c-: now-expression[-1][-2]._{v:47b} run scoreboard players operation #tmp_number0 c- /= #tmp_number1 c-
execute if data storage c-: now-expression[-1][-2]._{v:37b} run scoreboard players operation #tmp_number0 c- %= #tmp_number1 c-
execute store result storage c-: now-expression[-1][-1]._._ int 1 run scoreboard players get #tmp_number0 c-
function c-:parse/constant-register with storage c-: now-expression[-1][-1]._
data remove storage c-: now-expression[-1][-2]function c-:parse/expression/reduction/mulop/_3
data modify storage c-: now-function.code append value {s_:-2,v:mov}
execute store result storage c-: now-function.code[-1].s int 1 run scoreboard players add #tmpvar-count c- 1
data modify storage c-: now-function.code[-1].o set from storage c-: now-expression[-1][-2]._._
data modify storage c-: now-function.code[-1].o_ set from storage c-: now-expression[-1][-2]._.__
data modify storage c-: now-codeline.s_ set value -2
data modify storage c-: now-codeline.s set from storage c-: now-function.code[-1].s
data modify storage c-: now-codeline.o set from storage c-: now-expression[-1][-1]._._
data modify storage c-: now-codeline.o_ set from storage c-: now-expression[-1][-1]._.__
data modify storage c-: now-function.code append from storage c-: now-codeline
data modify storage c-: now-expression[-1][-1]._._ set from storage c-: now-codeline.s
data modify storage c-: now-expression[-1][-1]._.__ set value -2
data remove storage c-: now-expression[-1][-2]4.4.8.3 Comparison operation reduction
The basic situation of comparison operation reduction is the same as the previous two, although this operation has three operands in the intermediate language implementation.
function c-:parse/expression/reduction/relop/
data modify storage c-: now-codeline set value {}
execute if data storage c-: now-expression[-1][-2]._{v:60b} run data modify storage c-: now-codeline.v set value lt
execute if data storage c-: now-expression[-1][-2]._{v:62b} run data modify storage c-: now-codeline.v set value gt
execute if data storage c-: now-expression[-1][-2]._{v:75b} run data modify storage c-: now-codeline.v set value ne
execute if data storage c-: now-expression[-1][-2]._{v:76b} run data modify storage c-: now-codeline.v set value ge
execute if data storage c-: now-expression[-1][-2]._{v:77b} run data modify storage c-: now-codeline.v set value le
execute if data storage c-: now-expression[-1][-2]._{v:78b} run data modify storage c-: now-codeline.v set value eq
execute if data storage c-: now-codeline.v run return run function c-:parse/expression/reduction/relop/_function c-:parse/expression/reduction/relop/_
execute if data storage c-: now-expression[-1][-2]._{__:-2} run return run function c-:parse/expression/reduction/relop/_1
execute if data storage c-: now-expression[-1][-2]._{__:-100} if data storage c-: now-expression[-1][-1]._{__:-100} run return run function c-:parse/expression/reduction/relop/_2
execute unless data storage c-: now-expression[-1][-2]._{__:-2147483648} unless data storage c-: now-expression[-1][-1]._{__:-2147483648} run return run function c-:parse/expression/reduction/relop/_3
return run function c-:terminate {msg:"TypeError: void value not ignored as it ought to be"}function c-:parse/expression/reduction/relop/_1
data modify storage c-: now-codeline merge value {s_:-2,o_:-2}
data modify storage c-: now-codeline.s set from storage c-: now-expression[-1][-2]._._
data modify storage c-: now-codeline.o set from storage c-: now-expression[-1][-2]._._
data modify storage c-: now-codeline.o2 set from storage c-: now-expression[-1][-1]._._
data modify storage c-: now-codeline.o2_ set from storage c-: now-expression[-1][-1]._.__
data modify storage c-: now-function.code append from storage c-: now-codeline
data modify storage c-: now-expression[-1][-1]._ set from storage c-: now-expression[-1][-2]._
data remove storage c-: now-expression[-1][-2]function c-:parse/expression/reduction/relop/_2
execute store result score #tmp_number0 c- run data get storage c-: now-expression[-1][-2]._._
execute store result score #tmp_number1 c- run data get storage c-: now-expression[-1][-1]._._
execute if data storage c-: now-expression[-1][-2]._{v:60b} store result score #tmp_number0 c- if score #tmp_number0 c- < #tmp_number1 c-
execute if data storage c-: now-expression[-1][-2]._{v:62b} store result score #tmp_number0 c- if score #tmp_number0 c- > #tmp_number1 c-
execute if data storage c-: now-expression[-1][-2]._{v:75b} store result score #tmp_number0 c- unless score #tmp_number0 c- = #tmp_number1 c-
execute if data storage c-: now-expression[-1][-2]._{v:76b} store result score #tmp_number0 c- if score #tmp_number0 c- >= #tmp_number1 c-
execute if data storage c-: now-expression[-1][-2]._{v:77b} store result score #tmp_number0 c- if score #tmp_number0 c- <= #tmp_number1 c-
execute if data storage c-: now-expression[-1][-2]._{v:78b} store result score #tmp_number0 c- if score #tmp_number0 c- = #tmp_number1 c-
execute store result storage c-: now-expression[-1][-1]._._ int 1 run scoreboard players get #tmp_number0 c-
function c-:parse/constant-register with storage c-: now-expression[-1][-1]._
data remove storage c-: now-expression[-1][-2]function c-:parse/expression/reduction/relop/_3
data modify storage c-: now-codeline.s_ set value -2
execute store result storage c-: now-codeline.s int 1 run scoreboard players add #tmpvar-count c- 1
data modify storage c-: now-codeline.o set from storage c-: now-expression[-1][-2]._._
data modify storage c-: now-codeline.o_ set from storage c-: now-expression[-1][-2]._.__
data modify storage c-: now-codeline.o2 set from storage c-: now-expression[-1][-1]._._
data modify storage c-: now-codeline.o2_ set from storage c-: now-expression[-1][-1]._.__
data modify storage c-: now-function.code append from storage c-: now-codeline
data modify storage c-: now-expression[-1][-1]._._ set from storage c-: now-codeline.s
data modify storage c-: now-expression[-1][-1]._.__ set value -2
data remove storage c-: now-expression[-1][-2]4.4.8.4 Assignment reduction
There will only be one case of assignment reduction and no classification will be done. However, due to the right associativity of assignment, it needs to be run in a loop.
function c-:parse/expression/reduction/mov/
execute if function c-:parse/expression/reduction/mov/_ unless data storage c-: now-expression[-1][-1]._{__:void} run return run function c-:parse/expression/reduction/mov/function c-:parse/expression/reduction/mov/_
data modify storage c-: now-codeline set value {}
execute if data storage c-: now-expression[-1][-2]._{v:61b} run data modify storage c-: now-codeline.v set value mov
execute if data storage c-: now-expression[-1][-2]._{v:70b} run data modify storage c-: now-codeline.v set value add
execute if data storage c-: now-expression[-1][-2]._{v:71b} run data modify storage c-: now-codeline.v set value sub
execute if data storage c-: now-expression[-1][-2]._{v:72b} run data modify storage c-: now-codeline.v set value mul
execute if data storage c-: now-expression[-1][-2]._{v:73b} run data modify storage c-: now-codeline.v set value div
execute if data storage c-: now-expression[-1][-2]._{v:74b} run data modify storage c-: now-codeline.v set value mod
execute if data storage c-: now-codeline.v run return run function c-:parse/expression/reduction/mov/__
return failfunction c-:parse/expression/reduction/mov/__
data modify storage c-: now-codeline.s set from storage c-: now-expression[-1][-2]._._
data modify storage c-: now-codeline.s_ set from storage c-: now-expression[-1][-2]._.__
data modify storage c-: now-codeline.o set from storage c-: now-expression[-1][-1]._._
data modify storage c-: now-codeline.o_ set from storage c-: now-expression[-1][-1]._.__
data modify storage c-: now-function.code append from storage c-: now-codeline
data modify storage c-: now-expression[-1][-1]._ set from storage c-: now-expression[-1][-2]._
data remove storage c-: now-expression[-1][-2]
return 14.4.8.5 function call reduction
Each parameter will be a subexpression, and the final value of each parameter will be assigned to the newly created scoreboard. Then the function call will be officially started and a value will be returned (stored in the global scoreboard location corresponding to the function).
For ease of understanding, the possible intermediate codes are listed here as follows:
chain-add ; 在访问链上新增一层。
; <第一个参数的计分板运算>
mov arg1[0] , 5[temp] ; 将以上表达式的最终结果存入新建层的参数变量处。
; <第二个参数的计分板运算>
mov arg2[0] , 7[temp] ; 将以上表达式的最终结果存入新建层的参数变量处。
; ...
; <第n个参数的计分板运算>
mov argn[0] , 18[temp]
call function1 ; 运行函数(函数开始时会移动访问链标号与临时计分板标号)。
mov 19[temp] , function1[global] ; 将其返回值存入本函数的temp层。Since there are new levels in this process, here is thenow-variableAdd an empty list to ensure correct variable scope.
functionc-:parse/expression/reduction/call/start
data modify storage c-: now-function.code append value {v:chain-add}
data modify storage c-: now-variable append value []functionc-:parse/expression/reduction/call/arg
execute unless data storage c-: now-expression[-2][-1]._.arg[0] run return run function c-:terminate {msg:"TypeError: too many arguments to function"}
data modify storage c-: now-function.code append value {v:mov,s_:0}
data modify storage c-: now-function.code[-1].s set from storage c-: now-expression[-2][-1]._.arg[0].name
data modify storage c-: now-function.code[-1].o set from storage c-: now-expression[-1][0]._._
data modify storage c-: now-function.code[-1].o_ set from storage c-: now-expression[-1][0]._.__
data remove storage c-: now-expression[-2][-1]._.arg[0]functionc-:parse/expression/reduction/call/end
execute if data storage c-: now-expression[-1][-1]._.arg[0] run return run function c-:terminate {msg:"TypeError: too few arguments to function"}
data modify storage c-: now-function.code append value {v:call}
data modify storage c-: now-function.code[-1].f set from storage c-: now-expression[-1][-1]._._
data modify storage c-: now-function.code append value {s_:-2,v:mov,o_:-1}
execute store result storage c-: now-function.code[-1].s int 1 run scoreboard players add #tmpvar-count c- 1
data modify storage c-: now-function.code[-1].o set from storage c-: now-expression[-1][-1]._._
data remove storage c-: now-variable[-1]
execute store result storage c-: now-expression[-1][-1]._._ int 1 run scoreboard players get #tmpvar-count c-
data modify storage c-: now-expression[-1][-1]._{__:int}.__ set value -24.5 Top-down construction of non-expression parts
As mentioned before, we will use a top-down construction method for the non-expression part.
Since errors may occur during each level of analysis, we will track an error tag in each level of recursion. If an error is encountered during the execution of a certain level of analysis, the recursion will be terminated. This error flag is the same as the error flag of lexical analysis, that is, when the syntax analysis fails, the player's c-token scoreboard score will also be overwritten as the error score (127), and any ongoing analysis process will be terminated.
Notice
Due to some initialization requirements, the entrance to each layer of the subsequent analysis process is "this morpheme" (the morpheme that has been read into the scoreboard such as c-token) instead of "the next morpheme".
Therefore, if a certain layer is at the current morpheme position, it can be concluded that its part is over, and the corresponding function still needs to perform the "get morpheme" operation again to avoid infinite loops and abnormal behaviors.
4.5.1 Program layer
We determine the program layer (<program>) is level 0, looping to find global definitions. The bnf of this layer is expressed as follows:
<program> ::= <declaration-list>
<declaration-list> ::= <declaration-list> <declaration> | <declaration>Translated, it is a program<program>Always consists of a list, each item in the list is a statement<declaration>。
function c-:parse/start
data modify storage c-: variable set value []
data modify storage c-: now-variable set value []
data modify storage c-: now-function set value {}
data modify storage c-: now-declaration set value {}
data modify storage c-: now-expression set value []
scoreboard objectives remove c-data.-1
scoreboard objectives add c-data.-1 dummy
scoreboard objectives remove c-data.-100
scoreboard objectives add c-data.-100 dummy
function c-:lexical-analysis/start
function c-:parse/node/programfunction c-:parse/node/program
execute if score @s c-token = #end c-token run return 0
execute unless predicate c-:parse/type-specifier run return run function c-:terminate {msg:"SyntaxError: expected type-identifier before '%3$s' token"}
execute if predicate c-:parse/type-specifier run function c-:parse/node/declaration/type-specifier
execute unless score @s c-token = #error c-token run function c-:parse/node/program4.5.2 Global definition layer
The following is the bnf representation of the C-Minus language global definition: (The array function already belongs to the category of C-Minus extended variants, and we will not support arrays in the specific implementation for the time being.)
<declaration> ::= <var-declaration> | <fun-declaration>
<var-declaration> ::= <type-specifier> ID ; | <type-specifier> ID [ NUM ] ;
<type-specifier> ::= int | void
<fun-declaration> ::= <type-specifier> ID ( <params> ) <compound-stmt>
<params> ::= <param-list> | void
<param-list> ::= <param-list> , <param> | <param>
<param> ::= <type-specifier> ID | <type-specifier> ID [ ]Roughly translated:
- A C-Minus code file is composed of a series of global declarations (
<declaration>), these global declarations are of two types: variable declarations (<var-declaration>) and function definition (<fun-declaration>)。 - The first two lexemes of a declaration statement are each a type identifier (
<type-specifier>) with a variable name (ID), but starting from the third item:- The third item in the function definition is the left parenthesis, which represents the beginning of the parameter list (note: C cannot set the initial value of the parameter);
- The third item in the variable declaration might be
=(Assign an initial value, which can only be a constant),,(next variable declaration of the same type) or;(end of statement).
To identify these, we build nodes for this process in a very similar way to the lexical analysis stage.
4.5.2.1 Common content
function c-:parse/node/declaration/type-specifier
# -- THIS --
data modify storage c-: now-declaration set value {}
execute unless score @s c-token = #void c-reserved run data modify storage c-: now-declaration.type set value "int"
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s c-token = #name c-token run return run function c-:parse/node/declaration/name with storage c-: extract
# -- ERROR --
function c-:terminate {msg:"SyntaxError: expected identifier before '%3$s' token"}
# -- END --function c-:parse/node/declaration/name
# -- THIS --
$execute if data storage c-: variable[{name:"$(_)"}] run return run function c-:terminate {msg:"SyntaxError: redifinition of '%3$s'"}
data modify storage c-: now-declaration.name set from storage c-: extract._
# -- NEXT --
function c-:lexical-analysis/node/
$execute unless score @s c-token = #( c-chr unless data storage c-: now-declaration.type run return run function c-:terminate {msg:"TypeError: variable or field '$(_)' declared void"}
execute if score @s c-token = #( c-chr run return run function c-:parse/node/declaration/arg/start
execute if score @s c-token = #, c-chr run return run function c-:parse/node/declaration/sep
execute if score @s c-token = #= c-chr run return run function c-:parse/node/declaration/equal
execute if score @s c-token = #; c-chr run return run function c-:parse/node/declaration/var-end
# -- ERROR --
return run function c-:terminate {msg:"SyntaxError: expected '=', ',' or ';' before '%3$s' token"}
# -- END --4.5.2.2 Variable declaration branch
function c-:parse/node/declaration/equal
# -- THIS --
# -- NEXT --
function c-:lexical-analysis/node/
tag @s add c-exp-constant
function c-:parse/expression/start
tag @s remove c-exp-constant
# -- ERROR --
# -- END --
execute unless score @s c-token = #error c-token run return run function c-:parse/node/declaration/valuefunction c-:parse/node/declaration/value
# -- THIS --
data modify storage c-: now-declaration.initial set from storage c-: now-expression[-1][0]._._
# -- NEXT --
execute if score @s c-token = #, c-chr run return run function c-:parse/node/declaration/sep
execute if score @s c-token = #; c-chr run return run function c-:parse/node/declaration/var-end
# -- ERROR --
return run function c-:terminate {msg:"SyntaxError: expected ',' or ';' before '%3$s' token"}
# -- END --function c-:parse/node/declaration/sep
# -- THIS --
data modify storage c-: variable append from storage c-: now-declaration
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s c-token = #name c-token run return run function c-:parse/node/declaration/name with storage c-: extract
# -- ERROR --
return run function c-:terminate {msg:"SyntaxError: expected identifier before '%3$s' token"}
# -- END --function c-:parse/node/declaration/var-end
# -- THIS --
data modify storage c-: variable append from storage c-: now-declaration
# -- NEXT --
function c-:lexical-analysis/node/
# -- ERROR --
# -- END --4.5.2.3 function definition branch
function c-:parse/node/declaration/arg/start
# -- THIS --
data modify storage c-: now-function set from storage c-: now-declaration
data modify storage c-: now-variable append value []
data remove storage c-: now-declaration
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s c-token = #int c-reserved run return run function c-:parse/node/declaration/arg/type-specifier
execute if score @s c-token = #void c-reserved run return run function c-:parse/node/declaration/arg/void
execute if score @s c-token = #) c-chr run return run function c-:parse/node/declaration/arg/end
# -- ERROR --
function c-:terminate {msg:"SyntaxError: expected identifier or ')' before '%3$s' token"}
# -- END --function c-:parse/node/declaration/arg/type-specifier
# -- THIS --
data modify storage c-: now-declaration set value {type:"int"}
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s c-token = #name c-token run return run function c-:parse/node/declaration/arg/name with storage c-: extract
# -- ERROR --
function c-:terminate {msg:"SyntaxError: expected identifier"}
# -- END --function c-:parse/node/declaration/arg/void
# -- THIS --
data modify storage c-: now-function.arg set value []
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s c-token = #) c-chr run return run function c-:parse/node/declaration/arg/end
# -- ERROR --
execute if score @s c-token = #name c-token run return run function c-:terminate {msg:"TypeError: parameter has incomplete type"}
execute if score @s c-token = #, c-chr run return run function c-:terminate {msg:"TypeError: 'void' must be the only parameter"}
function c-:terminate {msg:"SyntaxError: expected ')'"}
# -- END --function c-:parse/node/declaration/arg/name
# -- THIS --
$execute if data storage c-: now-function.arg[{name:"$(_)"}] run return run function c-:parse/terminate {msg:"SyntaxError: redifinition of parameter '$(_)'"}
data modify storage c-: now-declaration.name set from storage c-: extract._
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s c-token = #, c-chr run return run function c-:parse/node/declaration/arg/sep
execute if score @s c-token = #) c-chr run return run function c-:parse/node/declaration/arg/end
# -- ERROR --
return run function c-:terminate {msg:"SyntaxError: expected ',' or ')' before '%3$s' token"}
# -- END --function c-:parse/node/declaration/arg/sep
# -- THIS --
data modify storage c-: now-function.arg append from storage c-: now-declaration
data modify storage c-: now-variable[-1] append from storage c-: now-declaration
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s c-token = #int c-reserved run return run function c-:parse/node/declaration/arg/type-specifier
execute if score @s c-token = #) c-chr run return run function c-:parse/node/declaration/arg/end
# -- ERROR --
execute if score @s c-token = #void c-reserved run return run function c-:terminate {msg:"TypeError: parameter has incomplete type"}
function c-:terminate {msg:"SyntaxError: expected identifier or ')' before '%3$s' token"}
# -- END --function c-:parse/node/declaration/arg/end
# -- THIS --
data modify storage c-: now-function.arg append from storage c-: now-declaration
data modify storage c-: variable append from storage c-: now-function
data modify storage c-: now-variable[-1] append from storage c-: now-declaration
# -- NEXT --
function c-:lexical-analysis/node/
# -- ERROR --
execute unless score @s c-token = #{ c-chr run return run function c-:terminate {msg:"SyntaxError: expected declaration specifiers before '%3$s' token"}
# -- END --
return run function c-:parse/node/declaration/funcfunction c-:parse/node/declaration/func
data modify storage c-: now-block set value [{chain:1b,func:1b}]
function c-:lexical-analysis/node/
function c-:parse/node/local/4.5.3 Local layer
The local layer is within a single function or block of code. For C-Minus, the following statement types may appear in the local layer: (For the convenience of readers, we do not use bnf format to express this part of the code format here.)
if (<expr>)<local>
while (<expr>)<local>
{<block>}
return <expr>;
return;
int <name>[=<expr>][,<name>[=<expr>]];
<expr>;function c-:parse/node/local/block-start(Note: The lexeme read at the beginning of the code block is curly brackets, so you need to jump back one lexeme before starting.)
function c-:lexical-analysis/node/
function c-:parse/node/local/startfunction c-:parse/node/local/start
data modify storage c-: now-block append value {}
return run function c-:parse/node/local/function c-:parse/node/local/
execute if score @s c-token = #} c-chr run return run function c-:parse/node/local/end
function c-:parse/node/local/_
execute unless score @s c-token = #error c-token run function c-:parse/node/local/function c-:parse/node/local/_
execute if score @s c-token = #{ c-chr run return run function c-:parse/node/local/block-start
execute if predicate c-:parse/type-specifier run return run function c-:parse/node/local/declaration/type-specifier
execute if score @s c-token = #if c-reserved run return run function c-:parse/node/local/if/
execute if score @s c-token = #while c-reserved run return run function c-:parse/node/local/while/
execute if score @s c-token = #return c-reserved if data storage c-: now-function.type run return run function c-:parse/node/local/return/
execute if score @s c-token = #return c-reserved unless data storage c-: now-function.type run return run function c-:parse/node/local/return/void
return run function c-:parse/node/local/expressionfunction c-:parse/node/local/end(We only add scope to the code block where the variable declaration appears, so remove the scope at the end of the code block. For functions, add a return 0 statement at the end.)
execute if data storage c-: now-block[-1].chain unless data storage c-: now-block[-1].func run data modify storage c-: now-function.code append value {v:chain-remove}
execute if data storage c-: now-block[-1].func run data modify storage c-: now-function.code append value {v:ret,s:0,s_:-100}
execute if data storage c-: now-block[-1].chain run data remove storage c-: now-variable[-1]
data remove storage c-: now-block[-1]
execute unless data storage c-: now-block[0] run function c-:parse/node/declaration/func_ with storage c-: now-function
function c-:lexical-analysis/node/function c-:parse/node/declaration/func_(If it is a function definition, move the code into the global variable storage variable.)
$data modify storage c-: variable[{name:"$(name)"}].code set from storage c-: now-function.code4.5.3.1 Single expression
function c-:parse/node/local/expression
# -- EXPR --
function c-:parse/expression/start
# -- , --
execute if score @s c-token = #, c-chr run return run function c-:parse/node/local/expression_sep
# -- ; --
execute unless score @s c-token = #; c-chr run return run function c-:terminate {msg:"SyntaxError: expected ';' before '%3$s' token"}
function c-:lexical-analysis/node/function c-:parse/node/local/expression_sep
function c-:lexical-analysis/node/
return run function c-:parse/node/local/expression4.5.3.2 Local variable declaration
The local variable declaration part is not much different from the structure of the global variable declaration except that the function cannot be defined and the initial value may not be a constant. For efficiency, we will only add separate scope levels to blocks of code where local variable declarations exist.
function c-:parse/node/local/type-identifier
# -- THIS --
data modify storage c-: now-declaration set value {}
data modify storage c-: now-declaration.type set value "int"
execute unless data storage c-: now-block[-1].chain run data modify storage c-: now-function.code append value {v:chain-add}
execute unless data storage c-: now-block[-1].chain run data modify storage c-: now-variable append value []
execute unless data storage c-: now-block[-1].chain run data modify storage c-: now-block[-1].chain set value 1b
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s c-token = #name c-token run return run function c-:parse/node/local/declaration/name with storage c-: extract
# -- ERROR --
function c-:terminate {msg:"SyntaxError: expected identifier before '%3$s' token"}
# -- END --function c-:parse/node/local/name
# -- THIS --
$execute if data storage c-: now-block.variable[{name:"$(_)"}] run return run function c-:terminate {msg:"SyntaxError: redifinition of '%3$s'"}
data modify storage c-: now-declaration.name set from storage c-: extract._
# -- NEXT --
function c-:lexical-analysis/node/
$execute unless data storage c-: now-declaration.type run return run function c-:terminate {msg:"TypeError: variable or field '$(_)' declared void"}
execute if score @s c-token = #, c-chr run return run function c-:parse/node/local/declaration/sep
execute if score @s c-token = #= c-chr run return run function c-:parse/node/local/declaration/equal
execute if score @s c-token = #; c-chr run return run function c-:parse/node/local/declaration/var-end
# -- ERROR --
return run function c-:terminate {msg:"SyntaxError: expected '=', ',' or ';' before '%3$s' token"}
# -- END --function c-:parse/node/local/equal
# -- THIS --
# -- NEXT --
function c-:lexical-analysis/node/
function c-:parse/expression/start
# -- ERROR --
# -- END --
execute unless score @s c-token = #error c-token run return run function c-:parse/node/local/declaration/valuefunction c-:parse/node/local/value
# -- THIS --
data modify storage c-: now-function.code append value {s_:0,v:mov}
data modify storage c-: now-function.code[-1].s set from storage c-: now-declaration.name
data modify storage c-: now-function.code[-1].o set from storage c-: now-expression[0][0]._._
data modify storage c-: now-function.code[-1].o_ set from storage c-: now-expression[0][0]._.__
# -- NEXT --
execute if score @s c-token = #, c-chr run return run function c-:parse/node/local/declaration/sep
execute if score @s c-token = #; c-chr run return run function c-:parse/node/local/declaration/var-end
# -- ERROR --
return run function c-:terminate {msg:"SyntaxError: expected ',' or ';' before '%3$s' token"}
# -- END --function c-:parse/node/local/sep
# -- THIS --
data modify storage c-: now-variable[-1] append from storage c-: now-declaration
# -- NEXT --
function c-:lexical-analysis/node/
execute if score @s c-token = #name c-token run return run function c-:parse/node/local/declaration/name with storage c-: extract
# -- ERROR --
return run function c-:terminate {msg:"SyntaxError: expected identifier before '%3$s' token"}
# -- END --function c-:parse/node/local/var-end
# -- THIS --
data modify storage c-: now-variable[-1] append from storage c-: now-declaration
# -- NEXT --
function c-:lexical-analysis/node/
# -- ERROR --
# -- END --4.5.3.3 if-else statement and while statement
if-else statements and while statements follow a fairly fixed format, so we can consolidate almost all nodes into one or two functions for continuous execution. Since we need to determine the size of the code block before going back to the above to add jumps, here we first use the stack to record the locations where jumps need to be added (if has 1, if-else has 2, and while has 2).
The specific intermediate code structure can be referred to as follows:
; if
if temp3 , label1 ; 若temp3为0则跳转至label1
; <if代码块内的内容>
jmp label2 ; 跳转至label2
; <label1>
; <else代码块内的内容>
; <label2>
; while
; <label0>
; <表达式计算结果至temp3>
if temp3 , label1 ; 若temp3为0则跳转至label1
; <while代码块内的内容>
jmp label0 ; 跳转至label0
; <label1>function c-:parse/node/local/while/
# -- WHILE --
data modify storage c-: now-declaration set value {v:if}
data modify storage c-: now-block append value {}
execute store result storage c-: now-block[-1].0 int 1 run data get storage c-: now-function.code
# -- ( --
function c-:lexical-analysis/node/
execute unless score @s c-token = #( c-chr run return run function c-:terminate {msg:"SyntaxError: expected '(' before '%3$s' token"}
# -- EXPR --
function c-:parse/node/local/while/expr
# -- ) --
execute unless score @s c-token = #) c-chr run return run function c-:terminate {msg:"SyntaxError: expected ')' before '%3$s' token"}
# -- EXPR / BLOCK / ; --
function c-:lexical-analysis/node/
function c-:parse/node/local/while/_
# -- LOOP --
data modify storage c-: now-function.code append value {v:jmp}
data modify storage c-: now-function.code[-1].b set from storage c-: now-block[-1].0
# -- JUMP --
function c-:parse/node/local/while/__ with storage c-: now-block[-1]
data remove storage c-: now-block[-1]function c-:parse/node/local/if/
# -- IF --
data modify storage c-: now-declaration set value {v:if}
data modify storage c-: now-block append value {}
# -- ( --
function c-:lexical-analysis/node/
execute unless score @s c-token = #( c-chr run return run function c-:terminate {msg:"SyntaxError: expected '(' before '%3$s' token"}
# -- EXPR --
function c-:parse/node/local/while/expr
# -- ) --
execute unless score @s c-token = #) c-chr run return run function c-:terminate {msg:"SyntaxError: expected ')' before '%3$s' token"}
# -- EXPR / BLOCK / ; --
function c-:lexical-analysis/node/
function c-:parse/node/local/while/_
# -- ELSE? --
execute if score @s c-token = #else c-reserved run return run function c-:parse/node/local/if/else
# -- JUMP --
function c-:parse/node/local/while/__ with storage c-: now-block[-1]
data remove storage c-: now-block[-1]function c-:parse/node/local/if/else
# -- ELSE --
execute store result storage c-: now-block[-1].2 int 1 run data get storage c-: now-function.code
data modify storage c-: now-function.code append value {v:jmp}
# -- JUMP1 --
function c-:parse/node/local/while/__ with storage c-: now-block[-1]
# -- EXPR / BLOCK / ; --
function c-:lexical-analysis/node/
function c-:parse/node/local/while/_
# -- JUMP2 --
function c-:parse/node/local/if/_ with storage c-: now-block[-1]
data remove storage c-: now-block[-1]Some auxiliary functions are as follows: (To save debugging overhead, if-else code blocks share some auxiliary functions with while code blocks.) function c-:parse/node/local/while/expr
function c-:lexical-analysis/node/
function c-:parse/expression/
data modify storage c-: now-declaration.s set from storage c-: now-expression[-1][0]._._
data modify storage c-: now-declaration.s_ set from storage c-: now-expression[-1][0]._.__
data remove storage c-: now-expression[-1]
execute if score @s c-token = #, c-chr run return run function c-:parse/node/local/while/expr
execute store result storage c-: now-block[-1].1 int 1 run data get storage c-: now-function.code
data modify storage c-: now-function.code append from storage c-: now-declarationfunction c-:parse/node/local/while/_(Actually, the local entry removes a variable declaration type.)
execute if score @s c-token = #{ c-chr run return run function c-:parse/node/local/block-start
execute if score @s c-token = #if c-reserved run return run function c-:parse/node/local/if/
execute if score @s c-token = #while c-reserved run return run function c-:parse/node/local/while/
execute if score @s c-token = #return c-reserved if data storage c-: now-function.type run return run function c-:parse/node/local/return/
execute if score @s c-token = #return c-reserved unless data storage c-: now-function.type run return run function c-:parse/node/local/return/void
return run function c-:parse/node/local/expressionfunction c-:parse/node/local/while/__(Used to handle jump 1.)
$execute store result storage c-: now-function.code[$(1)].b int 1 run data get storage c-: now-function.codefunction c-:parse/node/local/if/_(For handling jump 2.)
$execute store result storage c-: now-function.code[$(2)].b int 1 run data get storage c-: now-function.code4.5.3.4 return statement
The return statement has different entries for different types of functions. A function without a return value can only have a return statement without a return value, and a function with a return value must return with a return value. function c-:parse/node/local/return/void(Functions without return values use this entry.)
# -- RETURN (VOID) --
data modify storage c-: now-function.code append value {v:ret,s:0,s_:-100}
data modify storage c-: now-function.code[-1].f set from storage c-: now-function.name
# -- ; --
function c-:lexical-analysis/node/
execute unless score @s c-token = #; c-chr run return run function c-:terminate {msg:"TypeError: 'return' with a value, in function returning void"}function c-:parse/node/local/return/(Functions with return values use this entry.)
# -- RETURN (INT) --
data modify storage c-: now-declaration set value {v:ret}
# -- EXPR --
function c-:lexical-analysis/node/
execute if score @s c-token = #; c-chr run return run function c-:terminate {msg:"TypeError: 'return' with no value, in function returning non-void"}
function c-:parse/expression/start
data modify storage c-: now-declaration.s set from storage c-: now-expression[-1][0]._._
data modify storage c-: now-declaration.s_ set from storage c-: now-expression[-1][0]._.__
data modify storage c-: now-declaration.f set from storage c-: now-function.name
data remove storage c-: now-expression[-1]
# -- , --
execute if score @s c-token = #, c-chr run return run function c-:parse/node/local/return/sep
# -- ; --
execute unless score @s c-token = #; c-chr run return run function c-:terminate {msg:"SyntaxError: expected ';' before '%3$s' token"}
data modify storage c-: now-function.code append from storage c-: now-declaration
function c-:lexical-analysis/node/function c-:parse/node/local/return/sep
function c-:lexical-analysis/node/
function c-:parse/node/local/return/