!52 release: 合并 v0.6.0 版本至 main 分支
Merge pull request !52 from Luke/release/v0.6.0
This commit is contained in:
commit
f1069d6e5d
@ -69,7 +69,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: 软件版本/分支
|
label: 软件版本/分支
|
||||||
options:
|
options:
|
||||||
- v0.5.0
|
- v0.6.0
|
||||||
- main
|
- main
|
||||||
- dev
|
- dev
|
||||||
- 其他
|
- 其他
|
||||||
|
|||||||
11
.run/Bug2.run.xml
Normal file
11
.run/Bug2.run.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Bug2" type="Application" factoryName="Application" folderName="BugFarm">
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
|
<module name="Snow" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/BugFarm/Bug2 -o target/Bug2" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
11
.run/Bug3.run.xml
Normal file
11
.run/Bug3.run.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Bug3" type="Application" factoryName="Application" folderName="BugFarm">
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
|
<module name="Snow" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/BugFarm/Bug3 -o target/Bug3 --debug" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
11
.run/Bug4.run.xml
Normal file
11
.run/Bug4.run.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Bug4" type="Application" factoryName="Application" folderName="BugFarm">
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
|
<module name="Snow" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/BugFarm/Bug4 -o target/Bug4 --debug" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
11
.run/Bug5.run.xml
Normal file
11
.run/Bug5.run.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Bug5" type="Application" factoryName="Application" folderName="BugFarm">
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
|
<module name="Snow" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/BugFarm/Bug5 -o target/Bug5 " />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo1 -o target/Demo1 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo1 -o target/Demo1 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo10 -o target/Demo10 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo10 -o target/Demo10 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo11 -o target/Demo11 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo11 -o target/Demo11 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo12 -o target/Demo12 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo12 -o target/Demo12 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Demo13" type="Application" factoryName="Application" folderName="Demo">
|
<configuration default="false" name="Demo13" type="Application" factoryName="Application" folderName="Demo">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo13 -o target/Demo13 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo13 -o target/Demo13 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Demo14" type="Application" factoryName="Application" folderName="Demo">
|
<configuration default="false" name="Demo14" type="Application" factoryName="Application" folderName="Demo">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo14 -o target/Demo14 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo14 -o target/Demo14 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
10
.run/Demo15.run.xml
Normal file
10
.run/Demo15.run.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Demo15" type="Application" factoryName="Application" folderName="Demo">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
|
<module name="Snow" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo15 -o target/Demo15 --debug" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
10
.run/Demo16.run.xml
Normal file
10
.run/Demo16.run.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Demo16" type="Application" factoryName="Application" folderName="Demo">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
|
<module name="Snow" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo16 -o target/Demo16 --debug" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
10
.run/Demo17.run.xml
Normal file
10
.run/Demo17.run.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Demo17" type="Application" factoryName="Application" folderName="Demo">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
|
<module name="Snow" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo17 -o target/Demo17 --debug" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
10
.run/Demo18.run.xml
Normal file
10
.run/Demo18.run.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Demo18" type="Application" factoryName="Application" folderName="Demo">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
|
<module name="Snow" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo18 -o target/Demo18 --debug" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo2 -o target/Demo2 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo2 -o target/Demo2 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo3 -o target/Demo3 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo3 -o target/Demo3 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo4 -o target/Demo4 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo4 -o target/Demo4 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo5 -o target/Demo5 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo5 -o target/Demo5 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo6 -o target/Demo6 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo6 -o target/Demo6 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo7 -o target/Demo7 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo7 -o target/Demo7 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo8 -o target/Demo8 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo8 -o target/Demo8 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||||
<module name="Snow" />
|
<module name="Snow" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo9 -o target/Demo9 -debug" />
|
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo9 -o target/Demo9 --debug" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@ -5,6 +5,10 @@
|
|||||||
<toRun name="Demo11" type="Application" />
|
<toRun name="Demo11" type="Application" />
|
||||||
<toRun name="Demo12" type="Application" />
|
<toRun name="Demo12" type="Application" />
|
||||||
<toRun name="Demo13" type="Application" />
|
<toRun name="Demo13" type="Application" />
|
||||||
|
<toRun name="Demo14" type="Application" />
|
||||||
|
<toRun name="Demo15" type="Application" />
|
||||||
|
<toRun name="Demo16" type="Application" />
|
||||||
|
<toRun name="Demo17" type="Application" />
|
||||||
<toRun name="Demo2" type="Application" />
|
<toRun name="Demo2" type="Application" />
|
||||||
<toRun name="Demo3" type="Application" />
|
<toRun name="Demo3" type="Application" />
|
||||||
<toRun name="Demo4" type="Application" />
|
<toRun name="Demo4" type="Application" />
|
||||||
|
|||||||
@ -11,8 +11,8 @@
|
|||||||
<a href="https://gitee.com/jcnc-org/snow/blob/main/LICENSE">
|
<a href="https://gitee.com/jcnc-org/snow/blob/main/LICENSE">
|
||||||
<img src="https://img.shields.io/badge/%20license-Apache--2.0%20-blue" alt="">
|
<img src="https://img.shields.io/badge/%20license-Apache--2.0%20-blue" alt="">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://gitee.com/jcnc-org/snow/tree/v0.5.0/">
|
<a href="https://gitee.com/jcnc-org/snow/tree/v0.6.0/">
|
||||||
<img src="https://img.shields.io/badge/version-v0.5.0-blue" alt="">
|
<img src="https://img.shields.io/badge/version-v0.6.0-blue" alt="">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
33
playground/BugFarm/Bug2/Main.snow
Normal file
33
playground/BugFarm/Bug2/Main.snow
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
module: Main
|
||||||
|
import: os
|
||||||
|
function: main
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
loop:
|
||||||
|
init:
|
||||||
|
declare outer_i: int = 1
|
||||||
|
cond:
|
||||||
|
outer_i <= 10
|
||||||
|
step:
|
||||||
|
outer_i = outer_i + 1
|
||||||
|
body:
|
||||||
|
print(outer_i)
|
||||||
|
|
||||||
|
loop:
|
||||||
|
init:
|
||||||
|
// 注意这一行使用了外层循环的变量 outer_i
|
||||||
|
declare inter_j: int = outer_i
|
||||||
|
cond:
|
||||||
|
inter_j <= 10
|
||||||
|
step:
|
||||||
|
inter_j = inter_j + 1
|
||||||
|
body:
|
||||||
|
|
||||||
|
end body
|
||||||
|
end loop
|
||||||
|
|
||||||
|
end body
|
||||||
|
end loop
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
11
playground/BugFarm/Bug2/OS.snow
Normal file
11
playground/BugFarm/Bug2/OS.snow
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module: os
|
||||||
|
import: os
|
||||||
|
function: print
|
||||||
|
parameter:
|
||||||
|
declare i1: int
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
syscall("PRINT",i1)
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
14
playground/BugFarm/Bug3/Main.snow
Normal file
14
playground/BugFarm/Bug3/Main.snow
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module: Main
|
||||||
|
import: os
|
||||||
|
function: main
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
// 合法
|
||||||
|
declare b1: byte = 127b
|
||||||
|
declare s1: short = 32767s
|
||||||
|
declare i1: int = 2147483647
|
||||||
|
declare l1: long = 9223372036854775807L
|
||||||
|
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
11
playground/BugFarm/Bug3/OS.snow
Normal file
11
playground/BugFarm/Bug3/OS.snow
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module: os
|
||||||
|
import: os
|
||||||
|
function: print
|
||||||
|
parameter:
|
||||||
|
declare i1: int
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
syscall("PRINT",i1)
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
9
playground/BugFarm/Bug4/Main.snow
Normal file
9
playground/BugFarm/Bug4/Main.snow
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module: Main
|
||||||
|
import: ModuleB
|
||||||
|
function: main
|
||||||
|
return_type: int
|
||||||
|
body:
|
||||||
|
return ModuleB.fun()
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
8
playground/BugFarm/Bug4/a.snow
Normal file
8
playground/BugFarm/Bug4/a.snow
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module: ModuleA
|
||||||
|
function: fun
|
||||||
|
return_type: int
|
||||||
|
body:
|
||||||
|
return 123
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
9
playground/BugFarm/Bug4/b.snow
Normal file
9
playground/BugFarm/Bug4/b.snow
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module: ModuleB
|
||||||
|
import: ModuleA
|
||||||
|
function: fun
|
||||||
|
return_type: int
|
||||||
|
body:
|
||||||
|
return ModuleA.fun() + ModuleA.fun()
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
16
playground/BugFarm/Bug5/Main.snow
Normal file
16
playground/BugFarm/Bug5/Main.snow
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module: Main
|
||||||
|
import: os
|
||||||
|
globals:
|
||||||
|
declare sum: int = 0
|
||||||
|
function: main
|
||||||
|
parameter:
|
||||||
|
return_type: int
|
||||||
|
body:
|
||||||
|
sum = 20
|
||||||
|
|
||||||
|
os.print(sum)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
11
playground/BugFarm/Bug5/OS.snow
Normal file
11
playground/BugFarm/Bug5/OS.snow
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module: os
|
||||||
|
import: os
|
||||||
|
function: print
|
||||||
|
parameter:
|
||||||
|
declare i1: int
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
syscall("PRINT",i1)
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
@ -3,7 +3,7 @@ module: Main
|
|||||||
function: main
|
function: main
|
||||||
return_type: void
|
return_type: void
|
||||||
body:
|
body:
|
||||||
print(222)
|
os.print(222)
|
||||||
end body
|
end body
|
||||||
end function
|
end function
|
||||||
end module
|
end module
|
||||||
20
playground/Demo/Demo15/Main.snow
Normal file
20
playground/Demo/Demo15/Main.snow
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
module: Main
|
||||||
|
import: os
|
||||||
|
globals:
|
||||||
|
declare num2:int=10
|
||||||
|
function: main
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
declare num1:int=11
|
||||||
|
os.print(num1+num2+abc())
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
|
||||||
|
function: abc
|
||||||
|
return_type: int
|
||||||
|
body:
|
||||||
|
return 1
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
|
||||||
|
end module
|
||||||
11
playground/Demo/Demo15/OS.snow
Normal file
11
playground/Demo/Demo15/OS.snow
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module: os
|
||||||
|
import: os
|
||||||
|
function: print
|
||||||
|
parameter:
|
||||||
|
declare i1: int
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
syscall("PRINT",i1)
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
22
playground/Demo/Demo16/Main.snow
Normal file
22
playground/Demo/Demo16/Main.snow
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module: Main
|
||||||
|
import: os
|
||||||
|
function: main
|
||||||
|
return_type: int
|
||||||
|
body:
|
||||||
|
loop:
|
||||||
|
init:
|
||||||
|
declare i:int = 1
|
||||||
|
cond:
|
||||||
|
i <= 10
|
||||||
|
step:
|
||||||
|
i = i + 1
|
||||||
|
body:
|
||||||
|
if i % 2 == 0 then
|
||||||
|
os.print(i)
|
||||||
|
end if
|
||||||
|
end body
|
||||||
|
end loop
|
||||||
|
return 0
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
11
playground/Demo/Demo16/OS.snow
Normal file
11
playground/Demo/Demo16/OS.snow
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module: os
|
||||||
|
import: os
|
||||||
|
function: print
|
||||||
|
parameter:
|
||||||
|
declare i1: int
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
syscall("PRINT",i1)
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
23
playground/Demo/Demo17/Main.snow
Normal file
23
playground/Demo/Demo17/Main.snow
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
module: Main
|
||||||
|
import: os
|
||||||
|
function: main
|
||||||
|
return_type: int
|
||||||
|
body:
|
||||||
|
loop:
|
||||||
|
init:
|
||||||
|
declare i:int = 1
|
||||||
|
cond:
|
||||||
|
i <= 10
|
||||||
|
step:
|
||||||
|
i = i + 1
|
||||||
|
body:
|
||||||
|
if i % 2 == 0 then
|
||||||
|
os.print(i)
|
||||||
|
break
|
||||||
|
end if
|
||||||
|
end body
|
||||||
|
end loop
|
||||||
|
return 0
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
11
playground/Demo/Demo17/OS.snow
Normal file
11
playground/Demo/Demo17/OS.snow
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module: os
|
||||||
|
import: os
|
||||||
|
function: print
|
||||||
|
parameter:
|
||||||
|
declare i1: int
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
syscall("PRINT",i1)
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
43
playground/Demo/Demo18/Main.snow
Normal file
43
playground/Demo/Demo18/Main.snow
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
module: Main
|
||||||
|
import: os
|
||||||
|
function: main
|
||||||
|
return_type: int
|
||||||
|
body:
|
||||||
|
loop:
|
||||||
|
init:
|
||||||
|
declare i:int = 1
|
||||||
|
cond:
|
||||||
|
i <= 5
|
||||||
|
step:
|
||||||
|
i = i + 1
|
||||||
|
body:
|
||||||
|
if i % 2 == 0 then
|
||||||
|
continue
|
||||||
|
end if
|
||||||
|
if i > 3 then
|
||||||
|
break
|
||||||
|
end if
|
||||||
|
loop:
|
||||||
|
init:
|
||||||
|
declare j:int = 1
|
||||||
|
cond:
|
||||||
|
j <= 5
|
||||||
|
step:
|
||||||
|
j = j + 1
|
||||||
|
body:
|
||||||
|
if j == 4 then
|
||||||
|
break
|
||||||
|
end if
|
||||||
|
if j % 2 == 0 then
|
||||||
|
continue
|
||||||
|
end if
|
||||||
|
print(i)
|
||||||
|
print(j)
|
||||||
|
end body
|
||||||
|
end loop
|
||||||
|
end body
|
||||||
|
end loop
|
||||||
|
return 0
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
11
playground/Demo/Demo18/OS.snow
Normal file
11
playground/Demo/Demo18/OS.snow
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module: os
|
||||||
|
import: os
|
||||||
|
function: print
|
||||||
|
parameter:
|
||||||
|
declare i1: int
|
||||||
|
return_type: void
|
||||||
|
body:
|
||||||
|
syscall("PRINT",i1)
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
2
pom.xml
2
pom.xml
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<groupId>org.jcnc.snow</groupId>
|
<groupId>org.jcnc.snow</groupId>
|
||||||
<artifactId>Snow</artifactId>
|
<artifactId>Snow</artifactId>
|
||||||
<version>0.5.0</version>
|
<version>0.6.0</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
|||||||
@ -60,9 +60,9 @@ public final class CompileCommand implements CLICommand {
|
|||||||
|
|
||||||
List<String> argList = new ArrayList<>();
|
List<String> argList = new ArrayList<>();
|
||||||
|
|
||||||
// 保留用户在 cloud 模式下传入的 “run” / “-debug” 标志
|
// 保留用户在 cloud 模式下传入的 “run” / “--debug” 标志
|
||||||
for (String a : args) {
|
for (String a : args) {
|
||||||
if ("run".equals(a) || "-debug".equals(a)) {
|
if ("run".equals(a) || "--debug".equals(a)) {
|
||||||
argList.add(a);
|
argList.add(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,96 +5,83 @@ import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
|||||||
import org.jcnc.snow.compiler.ir.core.IRFunction;
|
import org.jcnc.snow.compiler.ir.core.IRFunction;
|
||||||
import org.jcnc.snow.compiler.ir.core.IRInstruction;
|
import org.jcnc.snow.compiler.ir.core.IRInstruction;
|
||||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 虚拟机代码生成器(VMCodeGenerator)
|
* VMCodeGenerator 负责将中间表示(IR)函数转换为目标虚拟机(VM)的指令序列。
|
||||||
* <p>
|
* <p>
|
||||||
* 本类作为指令生成器调度中心,不负责任何具体 IR 指令到 VM 指令的转换实现,
|
* 每个 IR 指令根据类型由对应的 InstructionGenerator 处理,并将结果输出到 VMProgramBuilder。
|
||||||
* 仅负责根据指令类型分发到对应的 {@link InstructionGenerator} 子类完成实际生成。
|
* 该类通过注册表(registry)实现 IR 到 VM 指令生成器的快速分发。
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* 工作流程简述:
|
|
||||||
* <ol>
|
|
||||||
* <li>接收一组已注册的 IR 指令生成器,并建立类型到生成器的映射表。</li>
|
|
||||||
* <li>遍历 IR 函数体的每条指令,根据类型找到对应的生成器,调用其 generate 方法生成 VM 指令。</li>
|
|
||||||
* <li>生成流程以函数为单位(beginFunction/endFunction)。</li>
|
|
||||||
* </ol>
|
|
||||||
*/
|
*/
|
||||||
public final class VMCodeGenerator {
|
public final class VMCodeGenerator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指令类型到生成器的注册表(调度表)。
|
* IR 指令类型到指令生成器的映射。
|
||||||
* <p>
|
* 每种 IRInstruction 都有对应的 InstructionGenerator 处理。
|
||||||
* 键: IR 指令类型(Class对象),
|
|
||||||
* 值: 对应的指令生成器实例。
|
|
||||||
* </p>
|
|
||||||
*/
|
*/
|
||||||
private final Map<Class<? extends IRInstruction>, InstructionGenerator<? extends IRInstruction>> registry;
|
private final Map<Class<? extends IRInstruction>, InstructionGenerator<? extends IRInstruction>> registry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 虚拟寄存器到槽号的映射表,由 RegisterAllocator 负责生成。
|
* 虚拟寄存器到 VM 局部槽位的映射表。
|
||||||
|
* 用于寄存器分配与指令生成。
|
||||||
*/
|
*/
|
||||||
private final Map<IRVirtualRegister, Integer> slotMap;
|
private final Map<IRVirtualRegister, Integer> slotMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 虚拟机程序构建器,用于输出 VM 指令。
|
* 输出目标 VM 程序的构建器。
|
||||||
|
* 提供 emit、beginFunction、endFunction 等接口。
|
||||||
*/
|
*/
|
||||||
private final VMProgramBuilder out;
|
private final VMProgramBuilder out;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前处理的函数名,用于部分指令生成逻辑(如主函数判断等)。
|
* 构造 VMCodeGenerator。
|
||||||
*/
|
|
||||||
private String currentFn;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造方法
|
|
||||||
*
|
*
|
||||||
* @param slotMap 虚拟寄存器到槽号的映射
|
* @param slotMap 虚拟寄存器到 VM 局部槽位的分配表
|
||||||
* @param out 虚拟机程序构建器
|
* @param out 输出 VM 程序的 builder
|
||||||
* @param generators 各类 IR 指令生成器集合,需预先构建
|
* @param generators 可用的 IR 指令生成器列表,每个类型只应有一个
|
||||||
*/
|
*/
|
||||||
public VMCodeGenerator(Map<IRVirtualRegister, Integer> slotMap,
|
public VMCodeGenerator(Map<IRVirtualRegister, Integer> slotMap,
|
||||||
VMProgramBuilder out,
|
VMProgramBuilder out,
|
||||||
List<InstructionGenerator<? extends IRInstruction>> generators) {
|
List<InstructionGenerator<? extends IRInstruction>> generators) {
|
||||||
this.slotMap = slotMap;
|
this.slotMap = slotMap;
|
||||||
this.out = out;
|
this.out = out;
|
||||||
// 按类型注册各 IR 指令生成器,建立不可变类型-生成器映射表
|
// 构建不可变的类型到生成器的注册表
|
||||||
this.registry = generators.stream()
|
this.registry = generators.stream()
|
||||||
.collect(Collectors.toUnmodifiableMap(InstructionGenerator::supportedClass, g -> g));
|
.collect(Collectors.toUnmodifiableMap(InstructionGenerator::supportedClass, g -> g));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 为一个 IR 函数生成虚拟机指令
|
* 将 IRFunction 生成对应 VM 代码,并写入输出。
|
||||||
*
|
*
|
||||||
* @param fn 待生成的 IR 函数对象
|
* <ol>
|
||||||
* @throws IllegalStateException 若遇到不支持的 IR 指令类型
|
* <li>调用 {@code out.beginFunction} 标记函数起始。</li>
|
||||||
|
* <li>遍历函数体的每条 IR 指令,查找对应 InstructionGenerator 并生成目标代码。</li>
|
||||||
|
* <li>对 main/main.xxx 函数追加 HALT 指令,其它函数追加 RET。</li>
|
||||||
|
* <li>调用 {@code out.endFunction} 结束函数。</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* @param fn 需要生成 VM 代码的 IRFunction
|
||||||
|
* @throws IllegalStateException 如果遇到不支持的 IR 指令类型
|
||||||
*/
|
*/
|
||||||
public void generate(IRFunction fn) {
|
public void generate(IRFunction fn) {
|
||||||
this.currentFn = fn.name();
|
String currentFn = fn.name();
|
||||||
|
|
||||||
/* 登记函数入口地址 —— 解决 CALL 未解析符号问题 */
|
|
||||||
out.beginFunction(currentFn);
|
out.beginFunction(currentFn);
|
||||||
|
|
||||||
/* 逐条分发 IR 指令给对应的生成器 */
|
|
||||||
for (IRInstruction ins : fn.body()) {
|
for (IRInstruction ins : fn.body()) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
// 查找合适的指令生成器
|
||||||
InstructionGenerator<IRInstruction> gen =
|
InstructionGenerator<IRInstruction> gen =
|
||||||
(InstructionGenerator<IRInstruction>) registry.get(ins.getClass());
|
(InstructionGenerator<IRInstruction>) registry.get(ins.getClass());
|
||||||
if (gen == null) {
|
if (gen == null) {
|
||||||
throw new IllegalStateException("Unsupported IR: " + ins);
|
throw new IllegalStateException("Unsupported IR: " + ins);
|
||||||
}
|
}
|
||||||
|
// 调用生成器生成对应的 VM 指令
|
||||||
gen.generate(ins, out, slotMap, currentFn);
|
gen.generate(ins, out, slotMap, currentFn);
|
||||||
}
|
}
|
||||||
|
// 结尾指令:main 函数统一用 HALT,其他函数用 RET
|
||||||
/* 强制补上函数结尾的返回/终止指令 */
|
String retOpcode = ("main".equals(currentFn) || currentFn.endsWith(".main")) ? "HALT" : "RET";
|
||||||
String retOpcode = "main".equals(currentFn) ? "HALT" : "RET";
|
|
||||||
out.emit(OpHelper.opcode(retOpcode));
|
out.emit(OpHelper.opcode(retOpcode));
|
||||||
|
|
||||||
/* 结束函数 */
|
|
||||||
out.endFunction();
|
out.endFunction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,109 +1,109 @@
|
|||||||
package org.jcnc.snow.compiler.backend.builder;
|
package org.jcnc.snow.compiler.backend.builder;
|
||||||
|
|
||||||
import org.jcnc.snow.vm.engine.VMOpCode;
|
import org.jcnc.snow.vm.engine.VMOpCode;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VMProgramBuilder: 构建线性 VM 程序(即按顺序存放所有 VM 指令)。
|
* VMProgramBuilder 用于构建虚拟机(VM)的最终指令列表。
|
||||||
* <p>
|
* <p>
|
||||||
* 本类用于编译器后端,将所有生成的 VM 指令(包括分支和调用指令)统一存储、管理。
|
* 主要职责:
|
||||||
* 支持符号(如函数入口、标签地址)的延迟解析与回填(fix-up)机制,
|
* <ul>
|
||||||
* 可在目标尚未定义时提前生成分支或调用指令,定义后自动修正。
|
* <li>维护代码指令序列和符号地址表</li>
|
||||||
* </p>
|
* <li>支持跨函数、标签跳转的延后修补(Call/Branch Fixup)</li>
|
||||||
* <p>
|
* <li>支持虚拟机本地槽位类型的管理(如 I/F...)</li>
|
||||||
* 常用于处理跨函数、跨标签的 CALL/JUMP 等复杂控制流,确保最终生成的 VM 指令地址一致正确。
|
* </ul>
|
||||||
* </p>
|
|
||||||
*/
|
*/
|
||||||
public final class VMProgramBuilder {
|
public final class VMProgramBuilder {
|
||||||
/** 未解析目标的 CALL 指令信息(待修补) */
|
|
||||||
|
/**
|
||||||
|
* 未知目标的 CALL 指令修补记录(待目标地址确定后修正)。
|
||||||
|
* @param index CALL 指令在 code 列表中的位置
|
||||||
|
* @param target 目标函数的全名
|
||||||
|
* @param nArgs 参数个数
|
||||||
|
*/
|
||||||
private record CallFix(int index, String target, int nArgs) {}
|
private record CallFix(int index, String target, int nArgs) {}
|
||||||
|
|
||||||
/** 未解析目标的分支指令(JUMP/IC_* 等待修补) */
|
/**
|
||||||
|
* 未知目标的分支指令修补记录(待目标标签确定后修正)。
|
||||||
|
* @param index 分支指令在 code 列表中的位置
|
||||||
|
* @param label 跳转目标标签名
|
||||||
|
*/
|
||||||
private record BranchFix(int index, String label) {}
|
private record BranchFix(int index, String label) {}
|
||||||
|
|
||||||
/** 占位符: 用于表示尚未确定的符号地址 */
|
/** 未解析地址的占位符,便于后期批量修补 */
|
||||||
private static final String PLACEHOLDER = "-1";
|
private static final String PLACEHOLDER = "-1";
|
||||||
|
|
||||||
/** 按顺序存放的 VM 指令文本 */
|
/** VM 指令列表 */
|
||||||
private final List<String> code = new ArrayList<>();
|
private final List<String> code = new ArrayList<>();
|
||||||
|
/** 槽位(寄存器)类型映射表(如 I/F...,用于类型检查或代码生成优化) */
|
||||||
// 虚拟机槽位编号到数据类型前缀的映射(如 0 -> 'I', 1 -> 'D' 等)
|
|
||||||
private final Map<Integer, Character> slotType = new HashMap<>();
|
private final Map<Integer, Character> slotType = new HashMap<>();
|
||||||
|
/** 符号(函数名/标签)到指令序号的映射表 */
|
||||||
/** 符号(如函数名、标签名)到其首地址(即指令序号/偏移量)的映射表
|
|
||||||
* 主要用于跳转和调用,定位具体的代码位置 */
|
|
||||||
private final Map<String, Integer> addr = new HashMap<>();
|
private final Map<String, Integer> addr = new HashMap<>();
|
||||||
|
/** 所有待修补的 CALL 指令集合 */
|
||||||
/** 所有待回填(fix-up)的 CALL 调用指令记录
|
|
||||||
* 由于被调用目标地址在编译时可能尚未确定,需要先记录,最终统一回填 */
|
|
||||||
private final List<CallFix> callFixes = new ArrayList<>();
|
private final List<CallFix> callFixes = new ArrayList<>();
|
||||||
|
/** 所有待修补的分支指令集合 */
|
||||||
/** 所有待回填(fix-up)的分支跳转指令记录
|
|
||||||
* 与 CALL 类似,分支指令的目标地址也可能需要编译后期再补充 */
|
|
||||||
private final List<BranchFix> branchFixes = new ArrayList<>();
|
private final List<BranchFix> branchFixes = new ArrayList<>();
|
||||||
|
/** 当前代码指针(已生成指令的数量/下一个指令的位置) */
|
||||||
/** 程序计数器(Program Counter),表示下一个生成指令将插入的位置 */
|
|
||||||
private int pc = 0;
|
private int pc = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置某个槽位对应的数据类型前缀
|
* 设置槽位(局部变量/虚拟寄存器)的类型前缀。
|
||||||
|
*
|
||||||
* @param slot 槽位编号
|
* @param slot 槽位编号
|
||||||
* @param prefix 类型前缀(如 'I' 表示 int,'D' 表示 double 等)
|
* @param prefix 类型前缀(如 'I', 'F')
|
||||||
*/
|
*/
|
||||||
public void setSlotType(int slot, char prefix) {
|
public void setSlotType(int slot, char prefix) {
|
||||||
slotType.put(slot, prefix);
|
slotType.put(slot, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某个槽位对应的数据类型前缀
|
* 获取槽位的类型前缀,默认为 'I'(整数类型)。
|
||||||
* 若未指定则返回默认类型 'I'(int)
|
*
|
||||||
* @param slot 槽位编号
|
* @param slot 槽位编号
|
||||||
* @return 类型前缀(如 'I', 'D' 等)
|
* @return 类型前缀字符
|
||||||
*/
|
*/
|
||||||
public char getSlotType(int slot) {
|
public char getSlotType(int slot) {
|
||||||
return slotType.getOrDefault(slot, 'I');
|
return slotType.getOrDefault(slot, 'I');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标记函数入口或标签,并尝试修补所有等候该符号的指令。
|
* 标记一个函数或标签的起始位置。
|
||||||
* @param name 符号名(函数名/标签名)
|
* <p>
|
||||||
|
* 1. 记录符号到当前 pc 的映射;
|
||||||
|
* 2. 立即尝试修补之前所有针对该符号的延后调用和分支。
|
||||||
|
*
|
||||||
|
* @param name 函数名或标签名(全限定名)
|
||||||
*/
|
*/
|
||||||
public void beginFunction(String name) {
|
public void beginFunction(String name) {
|
||||||
addr.put(name, pc); // 记录当前地址为入口
|
addr.put(name, pc);
|
||||||
patchCallFixes(name); // 修补所有待该符号的 CALL
|
patchCallFixes(name);
|
||||||
patchBranchFixes(name); // 修补所有待该符号的分支
|
patchBranchFixes(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** 函数结尾的处理(占位,无需特殊处理)。 */
|
||||||
* 结束函数(当前实现为空,方便 API 统一)。
|
public void endFunction() {}
|
||||||
*/
|
|
||||||
public void endFunction() { /* no-op */ }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写入一条 VM 指令或标签。
|
* 添加一条指令或标签到代码列表。
|
||||||
* <ul>
|
*
|
||||||
* <li>如果以冒号结尾,视为标签,仅登记其地址,不写入指令流,也不递增 pc。</li>
|
* @param line 指令字符串或标签字符串(若以冒号结尾为标签)
|
||||||
* <li>否则写入实际指令,并自增 pc。</li>
|
|
||||||
* </ul>
|
|
||||||
* @param line 一行 VM 指令文本或标签名(结尾有冒号)
|
|
||||||
*/
|
*/
|
||||||
public void emit(String line) {
|
public void emit(String line) {
|
||||||
if (line.endsWith(":")) { // 是标签定义行
|
if (line.endsWith(":")) {
|
||||||
|
// 标签定义
|
||||||
String label = line.substring(0, line.length() - 1);
|
String label = line.substring(0, line.length() - 1);
|
||||||
addr.put(label, pc); // 记录标签地址
|
addr.put(label, pc);
|
||||||
patchBranchFixes(label); // 修补所有以该标签为目标的分支指令
|
patchBranchFixes(label);
|
||||||
return; // 标签行不写入 code,不递增 pc
|
return;
|
||||||
}
|
}
|
||||||
code.add(line); // 普通指令写入 code
|
code.add(line);
|
||||||
pc++;
|
pc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成 CALL 指令。
|
* 添加一条 CALL 指令,若目标未定义则延后修补。
|
||||||
* 支持延迟修补: 若目标已知,直接写入地址;否则写入占位并登记 fix-up。
|
*
|
||||||
* @param target 目标函数名
|
* @param target 目标函数全名
|
||||||
* @param nArgs 参数个数
|
* @param nArgs 参数个数
|
||||||
*/
|
*/
|
||||||
public void emitCall(String target, int nArgs) {
|
public void emitCall(String target, int nArgs) {
|
||||||
@ -117,10 +117,10 @@ public final class VMProgramBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成分支(JUMP 或 IC_*)指令。
|
* 添加一条分支指令(如 JMP/BR/BEQ),若目标未定义则延后修补。
|
||||||
* 支持延迟修补机制。
|
*
|
||||||
* @param opcode 指令名
|
* @param opcode 指令操作码
|
||||||
* @param label 目标标签名
|
* @param label 跳转目标标签名
|
||||||
*/
|
*/
|
||||||
public void emitBranch(String opcode, String label) {
|
public void emitBranch(String opcode, String label) {
|
||||||
Integer a = resolve(label);
|
Integer a = resolve(label);
|
||||||
@ -133,13 +133,12 @@ public final class VMProgramBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建最终 VM 代码文本列表。
|
* 完成代码生成,输出最终 VM 指令序列。
|
||||||
* <ul>
|
* <p>
|
||||||
* <li>若存在未解析符号(CALL 或分支),则抛出异常。</li>
|
* 如果存在未修补的调用或分支,将抛出异常。
|
||||||
* <li>否则返回不可变指令流。</li>
|
*
|
||||||
* </ul>
|
* @return 指令序列(不可变)
|
||||||
* @return 完整 VM 指令流
|
* @throws IllegalStateException 如果存在未修补符号
|
||||||
* @throws IllegalStateException 若有未修补的符号引用
|
|
||||||
*/
|
*/
|
||||||
public List<String> build() {
|
public List<String> build() {
|
||||||
if (!callFixes.isEmpty() || !branchFixes.isEmpty()) {
|
if (!callFixes.isEmpty() || !branchFixes.isEmpty()) {
|
||||||
@ -151,27 +150,26 @@ public final class VMProgramBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析符号地址。若全限定名找不到则降级尝试简单名。
|
* 解析符号地址,仅支持全名精准匹配。
|
||||||
* @param sym 符号名
|
*
|
||||||
* @return 地址或 null(未定义)
|
* @param sym 符号全名
|
||||||
|
* @return 地址(指令序号),未找到返回 null
|
||||||
*/
|
*/
|
||||||
private Integer resolve(String sym) {
|
private Integer resolve(String sym) {
|
||||||
Integer a = addr.get(sym);
|
return addr.get(sym);
|
||||||
if (a == null && sym.contains(".")) {
|
|
||||||
a = addr.get(sym.substring(sym.lastIndexOf('.') + 1));
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修补所有以 name 为目标的 CALL 占位符。
|
* 修补所有等待目标函数 name 的 CALL 指令。
|
||||||
* @param name 新定义的函数名
|
* <p>
|
||||||
|
* 只支持全名精确修补,不做模糊查找或短名回退。
|
||||||
|
*
|
||||||
|
* @param name 目标函数全名
|
||||||
*/
|
*/
|
||||||
private void patchCallFixes(String name) {
|
private void patchCallFixes(String name) {
|
||||||
for (Iterator<CallFix> it = callFixes.iterator(); it.hasNext();) {
|
for (Iterator<CallFix> it = callFixes.iterator(); it.hasNext();) {
|
||||||
CallFix f = it.next();
|
CallFix f = it.next();
|
||||||
// 目标函数名完全匹配或后缀匹配(兼容全限定名)
|
if (f.target.equals(name)) {
|
||||||
if (f.target.equals(name) || f.target.endsWith("." + name)) {
|
|
||||||
code.set(f.index, VMOpCode.CALL + " " + addr.get(name) + " " + f.nArgs);
|
code.set(f.index, VMOpCode.CALL + " " + addr.get(name) + " " + f.nArgs);
|
||||||
it.remove();
|
it.remove();
|
||||||
}
|
}
|
||||||
@ -179,8 +177,9 @@ public final class VMProgramBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修补所有以 label 为目标的分支占位符。
|
* 修补所有等待目标 label 的分支指令。
|
||||||
* @param label 新定义的标签名
|
*
|
||||||
|
* @param label 目标标签
|
||||||
*/
|
*/
|
||||||
private void patchBranchFixes(String label) {
|
private void patchBranchFixes(String label) {
|
||||||
for (Iterator<BranchFix> it = branchFixes.iterator(); it.hasNext();) {
|
for (Iterator<BranchFix> it = branchFixes.iterator(); it.hasNext();) {
|
||||||
|
|||||||
@ -44,6 +44,7 @@ public final class IROpCodeMapper {
|
|||||||
opcodeMap.put(IROpCode.MUL_B8, "B_MUL");
|
opcodeMap.put(IROpCode.MUL_B8, "B_MUL");
|
||||||
opcodeMap.put(IROpCode.DIV_B8, "B_DIV");
|
opcodeMap.put(IROpCode.DIV_B8, "B_DIV");
|
||||||
opcodeMap.put(IROpCode.NEG_B8, "B_NEG");
|
opcodeMap.put(IROpCode.NEG_B8, "B_NEG");
|
||||||
|
opcodeMap.put(IROpCode.MOD_B8, "B_MOD");
|
||||||
|
|
||||||
// 整形16位算术运算映射
|
// 整形16位算术运算映射
|
||||||
opcodeMap.put(IROpCode.ADD_S16, "S_ADD");
|
opcodeMap.put(IROpCode.ADD_S16, "S_ADD");
|
||||||
@ -51,6 +52,7 @@ public final class IROpCodeMapper {
|
|||||||
opcodeMap.put(IROpCode.MUL_S16, "S_MUL");
|
opcodeMap.put(IROpCode.MUL_S16, "S_MUL");
|
||||||
opcodeMap.put(IROpCode.DIV_S16, "S_DIV");
|
opcodeMap.put(IROpCode.DIV_S16, "S_DIV");
|
||||||
opcodeMap.put(IROpCode.NEG_S16, "S_NEG");
|
opcodeMap.put(IROpCode.NEG_S16, "S_NEG");
|
||||||
|
opcodeMap.put(IROpCode.MOD_S16, "S_MOD");
|
||||||
|
|
||||||
// 整形32位算术运算映射
|
// 整形32位算术运算映射
|
||||||
opcodeMap.put(IROpCode.ADD_I32, "I_ADD");
|
opcodeMap.put(IROpCode.ADD_I32, "I_ADD");
|
||||||
@ -58,6 +60,7 @@ public final class IROpCodeMapper {
|
|||||||
opcodeMap.put(IROpCode.MUL_I32, "I_MUL");
|
opcodeMap.put(IROpCode.MUL_I32, "I_MUL");
|
||||||
opcodeMap.put(IROpCode.DIV_I32, "I_DIV");
|
opcodeMap.put(IROpCode.DIV_I32, "I_DIV");
|
||||||
opcodeMap.put(IROpCode.NEG_I32, "I_NEG");
|
opcodeMap.put(IROpCode.NEG_I32, "I_NEG");
|
||||||
|
opcodeMap.put(IROpCode.MOD_I32, "I_MOD");
|
||||||
|
|
||||||
// 整形64位算术运算映射
|
// 整形64位算术运算映射
|
||||||
opcodeMap.put(IROpCode.ADD_L64, "L_ADD");
|
opcodeMap.put(IROpCode.ADD_L64, "L_ADD");
|
||||||
@ -65,6 +68,7 @@ public final class IROpCodeMapper {
|
|||||||
opcodeMap.put(IROpCode.MUL_L64, "L_MUL");
|
opcodeMap.put(IROpCode.MUL_L64, "L_MUL");
|
||||||
opcodeMap.put(IROpCode.DIV_L64, "L_DIV");
|
opcodeMap.put(IROpCode.DIV_L64, "L_DIV");
|
||||||
opcodeMap.put(IROpCode.NEG_L64, "L_NEG");
|
opcodeMap.put(IROpCode.NEG_L64, "L_NEG");
|
||||||
|
opcodeMap.put(IROpCode.MOD_L64, "L_MOD");
|
||||||
|
|
||||||
// --- 32-bit floating point ---
|
// --- 32-bit floating point ---
|
||||||
|
|
||||||
@ -73,6 +77,7 @@ public final class IROpCodeMapper {
|
|||||||
opcodeMap.put(IROpCode.MUL_F32, "F_MUL");
|
opcodeMap.put(IROpCode.MUL_F32, "F_MUL");
|
||||||
opcodeMap.put(IROpCode.DIV_F32, "F_DIV");
|
opcodeMap.put(IROpCode.DIV_F32, "F_DIV");
|
||||||
opcodeMap.put(IROpCode.NEG_F32, "F_NEG");
|
opcodeMap.put(IROpCode.NEG_F32, "F_NEG");
|
||||||
|
opcodeMap.put(IROpCode.MOD_F32, "F_MOD");
|
||||||
|
|
||||||
// --- 64-bit floating point ---
|
// --- 64-bit floating point ---
|
||||||
opcodeMap.put(IROpCode.ADD_D64, "D_ADD");
|
opcodeMap.put(IROpCode.ADD_D64, "D_ADD");
|
||||||
@ -80,6 +85,7 @@ public final class IROpCodeMapper {
|
|||||||
opcodeMap.put(IROpCode.MUL_D64, "D_MUL");
|
opcodeMap.put(IROpCode.MUL_D64, "D_MUL");
|
||||||
opcodeMap.put(IROpCode.DIV_D64, "D_DIV");
|
opcodeMap.put(IROpCode.DIV_D64, "D_DIV");
|
||||||
opcodeMap.put(IROpCode.NEG_D64, "D_NEG");
|
opcodeMap.put(IROpCode.NEG_D64, "D_NEG");
|
||||||
|
opcodeMap.put(IROpCode.MOD_D64, "D_MOD");
|
||||||
|
|
||||||
// 比较运算映射
|
// 比较运算映射
|
||||||
// 8位整数比较运算映射
|
// 8位整数比较运算映射
|
||||||
|
|||||||
@ -157,7 +157,7 @@ public record ExpressionBuilder(IRContext ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建函数或方法调用表达式。
|
* 构建函数或方法调用表达式。模块内未限定调用会自动补全当前模块名。
|
||||||
*
|
*
|
||||||
* @param call AST 调用表达式节点
|
* @param call AST 调用表达式节点
|
||||||
* @return 存储调用结果的虚拟寄存器
|
* @return 存储调用结果的虚拟寄存器
|
||||||
@ -171,8 +171,18 @@ public record ExpressionBuilder(IRContext ctx) {
|
|||||||
// 成员方法调用,例如 obj.foo()
|
// 成员方法调用,例如 obj.foo()
|
||||||
case MemberExpressionNode m when m.object() instanceof IdentifierNode id
|
case MemberExpressionNode m when m.object() instanceof IdentifierNode id
|
||||||
-> id.name() + "." + m.member();
|
-> id.name() + "." + m.member();
|
||||||
// 普通函数调用
|
// 普通函数调用,如果未指定模块,自动补全当前模块名
|
||||||
case IdentifierNode id -> id.name();
|
case IdentifierNode id -> {
|
||||||
|
String current = ctx.getFunction().name();
|
||||||
|
int dot = current.lastIndexOf('.');
|
||||||
|
if (dot > 0) {
|
||||||
|
// 当前处于模块内函数(Module.func),补全为同模块下的全限定名
|
||||||
|
yield current.substring(0, dot) + "." + id.name();
|
||||||
|
} else {
|
||||||
|
// 顶层/脚本函数等不含模块前缀,保持原样
|
||||||
|
yield id.name();
|
||||||
|
}
|
||||||
|
}
|
||||||
// 其它情况暂不支持
|
// 其它情况暂不支持
|
||||||
default -> throw new IllegalStateException("不支持的调用目标: " + call.callee().getClass().getSimpleName());
|
default -> throw new IllegalStateException("不支持的调用目标: " + call.callee().getClass().getSimpleName());
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,24 +8,23 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
|
|||||||
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
||||||
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本类负责将解析生成的 AST 根节点列表转换为可执行的 IRProgram。
|
* IRProgramBuilder 负责将 AST 根节点(如模块、函数、顶层语句)转换为可执行的 IRProgram 实例。
|
||||||
*
|
* <p>
|
||||||
* <p>主要职责:
|
* 主要职责:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>遍历输入的顶层节点,识别 ModuleNode、FunctionNode 及脚本式顶层 StatementNode;</li>
|
* <li>遍历 AST 根节点,根据类型分别处理(模块、函数、顶层语句)。</li>
|
||||||
* <li>对 ModuleNode 中的所有函数节点调用 FunctionBuilder 构建 IRFunction 并添加至 IRProgram;</li>
|
* <li>对模块内的函数添加全限定名,并在函数体前注入全局变量声明。</li>
|
||||||
* <li>对单独的 FunctionNode 节点直接构建并纳入 IRProgram;</li>
|
* <li>将单独的顶层语句封装为特殊的 "_start" 函数。</li>
|
||||||
* <li>对顶层脚本式 StatementNode 自动封装为名称固定的“_start”函数,再行构建并纳入 IRProgram;</li>
|
|
||||||
* <li>对不支持的节点类型抛出 IllegalStateException,以确保编译流程严谨。</li>
|
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public final class IRProgramBuilder {
|
public final class IRProgramBuilder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建完整的 IRProgram 实例。
|
* 将解析生成的 AST 根节点列表转换为 IRProgram。
|
||||||
*
|
*
|
||||||
* @param roots 含 ModuleNode、FunctionNode 或 StatementNode 的顶层 AST 根节点列表
|
* @param roots 含 ModuleNode、FunctionNode 或 StatementNode 的顶层 AST 根节点列表
|
||||||
* @return 包含所有转换后 IRFunction 的 IRProgram 对象
|
* @return 包含所有转换后 IRFunction 的 IRProgram 对象
|
||||||
@ -35,17 +34,20 @@ public final class IRProgramBuilder {
|
|||||||
IRProgram irProgram = new IRProgram();
|
IRProgram irProgram = new IRProgram();
|
||||||
for (Node node : roots) {
|
for (Node node : roots) {
|
||||||
switch (node) {
|
switch (node) {
|
||||||
case ModuleNode moduleNode ->
|
case ModuleNode moduleNode -> {
|
||||||
// 模块节点: 批量构建并添加模块内所有函数
|
// 处理模块节点:遍历其中所有函数,统一用“模块名.函数名”作为全限定名
|
||||||
moduleNode.functions().forEach(f -> irProgram.add(buildFunction(f)));
|
for (FunctionNode f : moduleNode.functions()) {
|
||||||
|
irProgram.add(buildFunctionWithGlobals(moduleNode, f));
|
||||||
|
}
|
||||||
|
}
|
||||||
case FunctionNode functionNode ->
|
case FunctionNode functionNode ->
|
||||||
// 顶层函数节点: 直接构建并添加
|
// 处理顶层函数节点:直接构建为 IRFunction 并加入
|
||||||
irProgram.add(buildFunction(functionNode));
|
irProgram.add(buildFunction(functionNode));
|
||||||
case StatementNode statementNode ->
|
case StatementNode statementNode ->
|
||||||
// 脚本式顶层语句: 封装为“_start”函数后构建并添加
|
// 处理脚本式顶层语句:封装成 "_start" 函数后构建并添加
|
||||||
irProgram.add(buildFunction(wrapTopLevel(statementNode)));
|
irProgram.add(buildFunction(wrapTopLevel(statementNode)));
|
||||||
default ->
|
default ->
|
||||||
// 严格校验节点类型,遇不支持者立即失败
|
// 遇到未知类型节点,抛出异常
|
||||||
throw new IllegalStateException("Unsupported top-level node: " + node);
|
throw new IllegalStateException("Unsupported top-level node: " + node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,34 +55,75 @@ public final class IRProgramBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 利用 FunctionBuilder 将 FunctionNode 转换为 IRFunction。
|
* 构建带有模块全局声明“注入”的函数,并将函数名加上模块前缀,保证模块内函数名唯一。
|
||||||
|
* <p>
|
||||||
|
* 如果模块有全局声明,则这些声明会被插入到函数体前部。
|
||||||
*
|
*
|
||||||
* @param functionNode 待构建的 AST FunctionNode
|
* @param moduleNode 当前模块节点
|
||||||
* @return 构建完成的 IRFunction 实例
|
* @param functionNode 模块中的函数节点
|
||||||
|
* @return 包含全局声明、已加前缀函数名的 IRFunction
|
||||||
|
*/
|
||||||
|
private IRFunction buildFunctionWithGlobals(ModuleNode moduleNode, FunctionNode functionNode) {
|
||||||
|
// 拼接模块名和函数名,生成全限定名
|
||||||
|
String qualifiedName = moduleNode.name() + "." + functionNode.name();
|
||||||
|
// 若无全局声明,仅重命名后直接构建
|
||||||
|
if (moduleNode.globals() == null || moduleNode.globals().isEmpty()) {
|
||||||
|
return buildFunction(renameFunction(functionNode, qualifiedName));
|
||||||
|
}
|
||||||
|
// 若有全局声明,插入到函数体最前面
|
||||||
|
List<StatementNode> newBody = new ArrayList<>(moduleNode.globals().size() + functionNode.body().size());
|
||||||
|
newBody.addAll(moduleNode.globals());
|
||||||
|
newBody.addAll(functionNode.body());
|
||||||
|
FunctionNode wrapped = new FunctionNode(
|
||||||
|
qualifiedName,
|
||||||
|
functionNode.parameters(),
|
||||||
|
functionNode.returnType(),
|
||||||
|
newBody,
|
||||||
|
functionNode.context()
|
||||||
|
);
|
||||||
|
return buildFunction(wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成一个重命名的 FunctionNode(只修改函数名,其他属性保持不变)。
|
||||||
|
*
|
||||||
|
* @param fn 原始函数节点
|
||||||
|
* @param newName 新的函数名(通常为全限定名)
|
||||||
|
* @return 重命名后的 FunctionNode
|
||||||
|
*/
|
||||||
|
private FunctionNode renameFunction(FunctionNode fn, String newName) {
|
||||||
|
return new FunctionNode(
|
||||||
|
newName,
|
||||||
|
fn.parameters(),
|
||||||
|
fn.returnType(),
|
||||||
|
fn.body(),
|
||||||
|
fn.context()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建 IRFunction。
|
||||||
|
*
|
||||||
|
* @param functionNode 要转换的函数节点
|
||||||
|
* @return 转换结果 IRFunction
|
||||||
*/
|
*/
|
||||||
private IRFunction buildFunction(FunctionNode functionNode) {
|
private IRFunction buildFunction(FunctionNode functionNode) {
|
||||||
return new FunctionBuilder().build(functionNode);
|
return new FunctionBuilder().build(functionNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将单个脚本式顶层 StatementNode 封装为名称固定的“_start”函数节点。
|
* 将顶层语句节点封装成特殊的 "_start" 函数。
|
||||||
|
* <p>
|
||||||
|
* 这对于脚本式文件支持至关重要(即文件最外层直接写语句)。
|
||||||
*
|
*
|
||||||
* <p>封装规则:
|
* @param stmt 要封装的顶层语句
|
||||||
* <ul>
|
* @return 包装成 FunctionNode 的 "_start" 函数
|
||||||
* <li>函数名固定为“_start”;</li>
|
|
||||||
* <li>返回类型设为 null,由后续流程处理;</li>
|
|
||||||
* <li>参数列表为空;</li>
|
|
||||||
* <li>函数主体仅包含传入的单条语句。</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param stmt 待封装的顶层脚本语句节点
|
|
||||||
* @return 生成的 FunctionNode,用于后续 IRFunction 构建
|
|
||||||
*/
|
*/
|
||||||
private FunctionNode wrapTopLevel(StatementNode stmt) {
|
private FunctionNode wrapTopLevel(StatementNode stmt) {
|
||||||
return new FunctionNode(
|
return new FunctionNode(
|
||||||
"_start",
|
"_start",
|
||||||
null,
|
List.of(),
|
||||||
String.valueOf(List.of()),
|
"void",
|
||||||
List.of(stmt),
|
List.of(stmt),
|
||||||
new NodeContext(-1, -1, "")
|
new NodeContext(-1, -1, "")
|
||||||
);
|
);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
|||||||
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
||||||
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,6 +28,14 @@ public class StatementBuilder {
|
|||||||
* 表达式 IR 构建器,用于将表达式节点转为 IR 指令。
|
* 表达式 IR 构建器,用于将表达式节点转为 IR 指令。
|
||||||
*/
|
*/
|
||||||
private final ExpressionBuilder expr;
|
private final ExpressionBuilder expr;
|
||||||
|
/**
|
||||||
|
* break 目标标签栈(保存每层循环的结束标签)
|
||||||
|
*/
|
||||||
|
private final ArrayDeque<String> breakTargets = new ArrayDeque<>();
|
||||||
|
/**
|
||||||
|
* continue 目标标签栈(保存每层循环的 step 起始标签)
|
||||||
|
*/
|
||||||
|
private final ArrayDeque<String> continueTargets = new ArrayDeque<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造方法。
|
* 构造方法。
|
||||||
@ -89,21 +98,30 @@ public class StatementBuilder {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (stmt instanceof DeclarationNode decl) {
|
if (stmt instanceof DeclarationNode decl) {
|
||||||
// 变量声明,如 int a = 1;
|
// 变量声明语句(如 int a = 1;)
|
||||||
if (decl.getInitializer().isPresent()) {
|
if (decl.getInitializer().isPresent()) {
|
||||||
// 声明同时有初值
|
// 如果声明时带有初始值(如 int a = b;)
|
||||||
|
|
||||||
// 1. 设置声明变量的类型
|
// 1. 设置变量类型,便于表达式求值/指令生成时推断类型信息
|
||||||
ctx.setVarType(decl.getType());
|
ctx.setVarType(decl.getType());
|
||||||
|
|
||||||
IRVirtualRegister r = expr.build(decl.getInitializer().get());
|
// 2. 为当前声明的变量分配一个全新的虚拟寄存器
|
||||||
|
// 这样可以保证该变量和初始值表达式中的变量物理上独立,不会发生别名/串扰
|
||||||
|
IRVirtualRegister dest = ctx.newRegister();
|
||||||
|
|
||||||
// 2. 清除变量声明
|
// 3. 将初始值表达式的计算结果写入新分配的寄存器
|
||||||
|
// 即使初始值是某个已存在变量(如 outer_i),这里是值的拷贝
|
||||||
|
expr.buildInto(decl.getInitializer().get(), dest);
|
||||||
|
|
||||||
|
// 4. 清理类型设置,防止影响后续变量声明
|
||||||
ctx.clearVarType();
|
ctx.clearVarType();
|
||||||
|
|
||||||
ctx.getScope().declare(decl.getName(), decl.getType(), r);
|
// 5. 在作用域内将变量名与新分配的寄存器进行绑定
|
||||||
|
// 这样后续对该变量的任何操作都只会影响 dest,不会反向影响初值表达式中的源变量
|
||||||
|
ctx.getScope().declare(decl.getName(), decl.getType(), dest);
|
||||||
} else {
|
} else {
|
||||||
// 仅声明,无初值
|
// 仅声明变量,无初值(如 int a;)
|
||||||
|
// 在作用域内声明并分配新寄存器,但不进行初始化
|
||||||
ctx.getScope().declare(decl.getName(), decl.getType());
|
ctx.getScope().declare(decl.getName(), decl.getType());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -120,6 +138,22 @@ public class StatementBuilder {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (stmt instanceof BreakNode) {
|
||||||
|
// break 语句:跳转到当前最近一层循环的结束标签
|
||||||
|
if (breakTargets.isEmpty()) {
|
||||||
|
throw new IllegalStateException("`break` appears outside of a loop");
|
||||||
|
}
|
||||||
|
InstructionFactory.jmp(ctx, breakTargets.peek());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (stmt instanceof ContinueNode) {
|
||||||
|
// continue 语句:跳转到当前最近一层循环的 step 起始标签
|
||||||
|
if (continueTargets.isEmpty()) {
|
||||||
|
throw new IllegalStateException("`continue` appears outside of a loop");
|
||||||
|
}
|
||||||
|
InstructionFactory.jmp(ctx, continueTargets.peek());
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 不支持的语句类型
|
// 不支持的语句类型
|
||||||
throw new IllegalStateException("Unsupported statement: " + stmt.getClass().getSimpleName() + ": " + stmt);
|
throw new IllegalStateException("Unsupported statement: " + stmt.getClass().getSimpleName() + ": " + stmt);
|
||||||
}
|
}
|
||||||
@ -163,12 +197,24 @@ public class StatementBuilder {
|
|||||||
|
|
||||||
// 条件不满足则跳出循环
|
// 条件不满足则跳出循环
|
||||||
emitConditionalJump(loop.cond(), lblEnd);
|
emitConditionalJump(loop.cond(), lblEnd);
|
||||||
|
// 在进入循环体前,记录本层循环的结束标签,供 break 使用
|
||||||
|
breakTargets.push(lblEnd);
|
||||||
|
// 记录本层循环的 step 起始标签,供 continue 使用
|
||||||
|
String lblStep = ctx.newLabel();
|
||||||
|
continueTargets.push(lblStep);
|
||||||
|
try {
|
||||||
// 构建循环体
|
// 构建循环体
|
||||||
buildStatements(loop.body());
|
buildStatements(loop.body());
|
||||||
// 更新部分(如 for 的 i++)
|
} finally {
|
||||||
|
// 离开循环体时弹出标签,避免影响外层
|
||||||
|
breakTargets.pop();
|
||||||
|
continueTargets.pop();
|
||||||
|
}
|
||||||
|
// step 起始标签(所有 continue 会跳到这里)
|
||||||
|
InstructionFactory.label(ctx, lblStep);
|
||||||
if (loop.step() != null) build(loop.step());
|
if (loop.step() != null) build(loop.step());
|
||||||
|
|
||||||
// 跳回循环起点
|
// 回到 cond 检查
|
||||||
InstructionFactory.jmp(ctx, lblStart);
|
InstructionFactory.jmp(ctx, lblStart);
|
||||||
// 循环结束标签
|
// 循环结束标签
|
||||||
InstructionFactory.label(ctx, lblEnd);
|
InstructionFactory.label(ctx, lblEnd);
|
||||||
|
|||||||
@ -25,11 +25,12 @@ public enum IROpCode {
|
|||||||
|
|
||||||
|
|
||||||
/* ───── 算术运算(8位整数: byte)───── */
|
/* ───── 算术运算(8位整数: byte)───── */
|
||||||
ADD_B8, // 8位整型加法: a = b + c
|
ADD_B8, // 8位整型加法:
|
||||||
SUB_B8, // 8位整型减法: a = b - c
|
SUB_B8, // 8位整型减法:
|
||||||
MUL_B8, // 8位整型乘法: a = b * c
|
MUL_B8, // 8位整型乘法:
|
||||||
DIV_B8, // 8位整型除法: a = b / c
|
DIV_B8, // 8位整型除法:
|
||||||
NEG_B8, // 8位整型取负: a = -b
|
NEG_B8, // 8位整型取负:
|
||||||
|
MOD_B8, // 8位整型取余
|
||||||
|
|
||||||
/* ───── 算术运算(16位整数: short)───── */
|
/* ───── 算术运算(16位整数: short)───── */
|
||||||
ADD_S16, // 16位整型加法
|
ADD_S16, // 16位整型加法
|
||||||
@ -37,6 +38,7 @@ public enum IROpCode {
|
|||||||
MUL_S16, // 16位整型乘法
|
MUL_S16, // 16位整型乘法
|
||||||
DIV_S16, // 16位整型除法
|
DIV_S16, // 16位整型除法
|
||||||
NEG_S16, // 16位整型取负
|
NEG_S16, // 16位整型取负
|
||||||
|
MOD_S16, // 16位整型取余
|
||||||
|
|
||||||
/* ───── 算术运算(32位整数: int)───── */
|
/* ───── 算术运算(32位整数: int)───── */
|
||||||
ADD_I32, // 32位整型加法
|
ADD_I32, // 32位整型加法
|
||||||
@ -44,6 +46,7 @@ public enum IROpCode {
|
|||||||
MUL_I32, // 32位整型乘法
|
MUL_I32, // 32位整型乘法
|
||||||
DIV_I32, // 32位整型除法
|
DIV_I32, // 32位整型除法
|
||||||
NEG_I32, // 32位整型取负
|
NEG_I32, // 32位整型取负
|
||||||
|
MOD_I32, // 32位整型取余
|
||||||
|
|
||||||
/* ───── 算术运算(64位整数: long)───── */
|
/* ───── 算术运算(64位整数: long)───── */
|
||||||
ADD_L64, // 64位整型加法
|
ADD_L64, // 64位整型加法
|
||||||
@ -51,6 +54,7 @@ public enum IROpCode {
|
|||||||
MUL_L64, // 64位整型乘法
|
MUL_L64, // 64位整型乘法
|
||||||
DIV_L64, // 64位整型除法
|
DIV_L64, // 64位整型除法
|
||||||
NEG_L64, // 64位整型取负
|
NEG_L64, // 64位整型取负
|
||||||
|
MOD_L64, // 64位整型取余
|
||||||
|
|
||||||
/* ───── 算术运算(32位浮点数: float)───── */
|
/* ───── 算术运算(32位浮点数: float)───── */
|
||||||
ADD_F32, // 32位浮点加法
|
ADD_F32, // 32位浮点加法
|
||||||
@ -58,6 +62,7 @@ public enum IROpCode {
|
|||||||
MUL_F32, // 32位浮点乘法
|
MUL_F32, // 32位浮点乘法
|
||||||
DIV_F32, // 32位浮点除法
|
DIV_F32, // 32位浮点除法
|
||||||
NEG_F32, // 32位浮点取负
|
NEG_F32, // 32位浮点取负
|
||||||
|
MOD_F32, // 32位浮点取余
|
||||||
|
|
||||||
/* ───── 算术运算(64位浮点数: double)───── */
|
/* ───── 算术运算(64位浮点数: double)───── */
|
||||||
ADD_D64, // 64位浮点加法
|
ADD_D64, // 64位浮点加法
|
||||||
@ -65,6 +70,7 @@ public enum IROpCode {
|
|||||||
MUL_D64, // 64位浮点乘法
|
MUL_D64, // 64位浮点乘法
|
||||||
DIV_D64, // 64位浮点除法
|
DIV_D64, // 64位浮点除法
|
||||||
NEG_D64, // 64位浮点取负
|
NEG_D64, // 64位浮点取负
|
||||||
|
MOD_D64, // 64位浮点取余
|
||||||
|
|
||||||
/* ───── 逻辑与比较运算指令(8位整数: byte) ───── */
|
/* ───── 逻辑与比较运算指令(8位整数: byte) ───── */
|
||||||
CMP_BEQ, // 8位整数相等比较: a == b
|
CMP_BEQ, // 8位整数相等比较: a == b
|
||||||
|
|||||||
@ -6,41 +6,57 @@ import java.util.Map;
|
|||||||
* 操作符与IR操作码映射表,统一管理所有类型的算术和比较操作映射。
|
* 操作符与IR操作码映射表,统一管理所有类型的算术和比较操作映射。
|
||||||
*/
|
*/
|
||||||
public final class IROpCodeMappings {
|
public final class IROpCodeMappings {
|
||||||
private IROpCodeMappings() {} // 禁止实例化
|
|
||||||
|
|
||||||
// 8位整型运算符映射
|
// 8位整型运算符映射
|
||||||
public static final Map<String, IROpCode> OP_B8 = Map.of(
|
public static final Map<String, IROpCode> OP_B8 = Map.of(
|
||||||
"+", IROpCode.ADD_B8, "-", IROpCode.SUB_B8,
|
"+", IROpCode.ADD_B8,
|
||||||
"*", IROpCode.MUL_B8, "/", IROpCode.DIV_B8
|
"-", IROpCode.SUB_B8,
|
||||||
|
"*", IROpCode.MUL_B8,
|
||||||
|
"/", IROpCode.DIV_B8,
|
||||||
|
"%", IROpCode.MOD_B8
|
||||||
);
|
);
|
||||||
// 16位整型
|
// 16位整型
|
||||||
public static final Map<String, IROpCode> OP_S16 = Map.of(
|
public static final Map<String, IROpCode> OP_S16 = Map.of(
|
||||||
"+", IROpCode.ADD_S16, "-", IROpCode.SUB_S16,
|
"+", IROpCode.ADD_S16,
|
||||||
"*", IROpCode.MUL_S16, "/", IROpCode.DIV_S16
|
"-", IROpCode.SUB_S16,
|
||||||
|
"*", IROpCode.MUL_S16,
|
||||||
|
"/", IROpCode.DIV_S16,
|
||||||
|
"%", IROpCode.MOD_S16
|
||||||
);
|
);
|
||||||
// 32位整型
|
// 32位整型
|
||||||
public static final Map<String, IROpCode> OP_I32 = Map.of(
|
public static final Map<String, IROpCode> OP_I32 = Map.of(
|
||||||
"+", IROpCode.ADD_I32, "-", IROpCode.SUB_I32,
|
"+", IROpCode.ADD_I32,
|
||||||
"*", IROpCode.MUL_I32, "/", IROpCode.DIV_I32
|
"-", IROpCode.SUB_I32,
|
||||||
|
"*", IROpCode.MUL_I32,
|
||||||
|
"/", IROpCode.DIV_I32,
|
||||||
|
"%", IROpCode.MOD_I32
|
||||||
);
|
);
|
||||||
// 64位长整型
|
// 64位长整型
|
||||||
public static final Map<String, IROpCode> OP_L64 = Map.of(
|
public static final Map<String, IROpCode> OP_L64 = Map.of(
|
||||||
"+", IROpCode.ADD_L64, "-", IROpCode.SUB_L64,
|
"+", IROpCode.ADD_L64,
|
||||||
"*", IROpCode.MUL_L64, "/", IROpCode.DIV_L64
|
"-", IROpCode.SUB_L64,
|
||||||
|
"*", IROpCode.MUL_L64,
|
||||||
|
"/", IROpCode.DIV_L64,
|
||||||
|
"%", IROpCode.MOD_L64
|
||||||
);
|
);
|
||||||
// 32位浮点型
|
// 32位浮点型
|
||||||
public static final Map<String, IROpCode> OP_F32 = Map.of(
|
public static final Map<String, IROpCode> OP_F32 = Map.of(
|
||||||
"+", IROpCode.ADD_F32, "-", IROpCode.SUB_F32,
|
"+", IROpCode.ADD_F32,
|
||||||
"*", IROpCode.MUL_F32, "/", IROpCode.DIV_F32
|
"-", IROpCode.SUB_F32,
|
||||||
|
"*", IROpCode.MUL_F32,
|
||||||
|
"/", IROpCode.DIV_F32,
|
||||||
|
"%", IROpCode.MOD_F32
|
||||||
);
|
);
|
||||||
// 64位双精度浮点型
|
// 64位双精度浮点型
|
||||||
public static final Map<String, IROpCode> OP_D64 = Map.of(
|
public static final Map<String, IROpCode> OP_D64 = Map.of(
|
||||||
"+", IROpCode.ADD_D64, "-", IROpCode.SUB_D64,
|
"+", IROpCode.ADD_D64,
|
||||||
"*", IROpCode.MUL_D64, "/", IROpCode.DIV_D64
|
"-", IROpCode.SUB_D64,
|
||||||
|
"*", IROpCode.MUL_D64,
|
||||||
|
"/", IROpCode.DIV_D64,
|
||||||
|
"%", IROpCode.MOD_D64
|
||||||
);
|
);
|
||||||
|
/**
|
||||||
/* ────── 比较运算符映射 ────── */
|
* 8-bit(byte)比较
|
||||||
/** 8-bit(byte)比较 */
|
*/
|
||||||
public static final Map<String, IROpCode> CMP_B8 = Map.of(
|
public static final Map<String, IROpCode> CMP_B8 = Map.of(
|
||||||
"==", IROpCode.CMP_BEQ,
|
"==", IROpCode.CMP_BEQ,
|
||||||
"!=", IROpCode.CMP_BNE,
|
"!=", IROpCode.CMP_BNE,
|
||||||
@ -50,7 +66,10 @@ public final class IROpCodeMappings {
|
|||||||
">=", IROpCode.CMP_BGE
|
">=", IROpCode.CMP_BGE
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 16-bit(short)比较 */
|
/* ────── 比较运算符映射 ────── */
|
||||||
|
/**
|
||||||
|
* 16-bit(short)比较
|
||||||
|
*/
|
||||||
public static final Map<String, IROpCode> CMP_S16 = Map.of(
|
public static final Map<String, IROpCode> CMP_S16 = Map.of(
|
||||||
"==", IROpCode.CMP_SEQ,
|
"==", IROpCode.CMP_SEQ,
|
||||||
"!=", IROpCode.CMP_SNE,
|
"!=", IROpCode.CMP_SNE,
|
||||||
@ -59,8 +78,9 @@ public final class IROpCodeMappings {
|
|||||||
"<=", IROpCode.CMP_SLE,
|
"<=", IROpCode.CMP_SLE,
|
||||||
">=", IROpCode.CMP_SGE
|
">=", IROpCode.CMP_SGE
|
||||||
);
|
);
|
||||||
|
/**
|
||||||
/** 32-bit(int)比较 */
|
* 32-bit(int)比较
|
||||||
|
*/
|
||||||
public static final Map<String, IROpCode> CMP_I32 = Map.of(
|
public static final Map<String, IROpCode> CMP_I32 = Map.of(
|
||||||
"==", IROpCode.CMP_IEQ,
|
"==", IROpCode.CMP_IEQ,
|
||||||
"!=", IROpCode.CMP_INE,
|
"!=", IROpCode.CMP_INE,
|
||||||
@ -69,8 +89,9 @@ public final class IROpCodeMappings {
|
|||||||
"<=", IROpCode.CMP_ILE,
|
"<=", IROpCode.CMP_ILE,
|
||||||
">=", IROpCode.CMP_IGE
|
">=", IROpCode.CMP_IGE
|
||||||
);
|
);
|
||||||
|
/**
|
||||||
/** 64-bit(long)比较 */
|
* 64-bit(long)比较
|
||||||
|
*/
|
||||||
public static final Map<String, IROpCode> CMP_L64 = Map.of(
|
public static final Map<String, IROpCode> CMP_L64 = Map.of(
|
||||||
"==", IROpCode.CMP_LEQ,
|
"==", IROpCode.CMP_LEQ,
|
||||||
"!=", IROpCode.CMP_LNE,
|
"!=", IROpCode.CMP_LNE,
|
||||||
@ -79,8 +100,9 @@ public final class IROpCodeMappings {
|
|||||||
"<=", IROpCode.CMP_LLE,
|
"<=", IROpCode.CMP_LLE,
|
||||||
">=", IROpCode.CMP_LGE
|
">=", IROpCode.CMP_LGE
|
||||||
);
|
);
|
||||||
|
/**
|
||||||
/** 32-bit(float)比较 */
|
* 32-bit(float)比较
|
||||||
|
*/
|
||||||
public static final Map<String, IROpCode> CMP_F32 = Map.of(
|
public static final Map<String, IROpCode> CMP_F32 = Map.of(
|
||||||
"==", IROpCode.CMP_FEQ,
|
"==", IROpCode.CMP_FEQ,
|
||||||
"!=", IROpCode.CMP_FNE,
|
"!=", IROpCode.CMP_FNE,
|
||||||
@ -89,8 +111,9 @@ public final class IROpCodeMappings {
|
|||||||
"<=", IROpCode.CMP_FLE,
|
"<=", IROpCode.CMP_FLE,
|
||||||
">=", IROpCode.CMP_FGE
|
">=", IROpCode.CMP_FGE
|
||||||
);
|
);
|
||||||
|
/**
|
||||||
/** 64-bit(double)比较 */
|
* 64-bit(double)比较
|
||||||
|
*/
|
||||||
public static final Map<String, IROpCode> CMP_D64 = Map.of(
|
public static final Map<String, IROpCode> CMP_D64 = Map.of(
|
||||||
"==", IROpCode.CMP_DEQ,
|
"==", IROpCode.CMP_DEQ,
|
||||||
"!=", IROpCode.CMP_DNE,
|
"!=", IROpCode.CMP_DNE,
|
||||||
@ -99,4 +122,7 @@ public final class IROpCodeMappings {
|
|||||||
"<=", IROpCode.CMP_DLE,
|
"<=", IROpCode.CMP_DLE,
|
||||||
">=", IROpCode.CMP_DGE
|
">=", IROpCode.CMP_DGE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private IROpCodeMappings() {
|
||||||
|
} // 禁止实例化
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,10 @@ public class TokenFactory {
|
|||||||
/**
|
/**
|
||||||
* 语言的保留关键字集合。
|
* 语言的保留关键字集合。
|
||||||
*/
|
*/
|
||||||
private static final Set<String> KEYWORDS = Set.of("module", "function", "parameter", "return_type", "body", "end", "if", "then", "else", "loop", "declare", "return", "import", "init", "cond", "step");
|
private static final Set<String> KEYWORDS = Set.of
|
||||||
|
("module", "function", "parameter", "return_type", "body", "end",
|
||||||
|
"if", "then", "else", "loop", "declare", "return", "import", "init",
|
||||||
|
"cond", "step", "globals", "break", "continue");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内置类型名称集合,如 int、string 等。
|
* 内置类型名称集合,如 int、string 等。
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code BreakNode} 表示循环体中的 break 语句。
|
||||||
|
* 出现时应立即终止当前(最内层)循环。
|
||||||
|
*/
|
||||||
|
public record BreakNode(NodeContext context) implements StatementNode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "break@" + context;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code ContinueNode} 表示循环体中的 continue 语句节点。
|
||||||
|
* <p>
|
||||||
|
* continue 语句用于跳过当前循环剩余部分,直接进入下一次循环的 step→cond 阶段。
|
||||||
|
* 该节点仅作为语法树中的一种语句类型出现。
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public record ContinueNode(NodeContext context) implements StatementNode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "continue";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@ import java.util.StringJoiner;
|
|||||||
public record ModuleNode(
|
public record ModuleNode(
|
||||||
String name,
|
String name,
|
||||||
List<ImportNode> imports,
|
List<ImportNode> imports,
|
||||||
|
List<DeclarationNode> globals,
|
||||||
List<FunctionNode> functions,
|
List<FunctionNode> functions,
|
||||||
NodeContext context
|
NodeContext context
|
||||||
) implements Node {
|
) implements Node {
|
||||||
@ -33,12 +34,17 @@ public record ModuleNode(
|
|||||||
for (ImportNode imp : imports) {
|
for (ImportNode imp : imports) {
|
||||||
importJoiner.add(imp.moduleName());
|
importJoiner.add(imp.moduleName());
|
||||||
}
|
}
|
||||||
|
StringJoiner globalJoiner = new StringJoiner(", ");
|
||||||
|
for (DeclarationNode g : globals) {
|
||||||
|
globalJoiner.add(g.getType() + " " + g.getName());
|
||||||
|
}
|
||||||
StringJoiner funcJoiner = new StringJoiner(", ");
|
StringJoiner funcJoiner = new StringJoiner(", ");
|
||||||
for (FunctionNode fn : functions) {
|
for (FunctionNode fn : functions) {
|
||||||
funcJoiner.add(fn.name());
|
funcJoiner.add(fn.name());
|
||||||
}
|
}
|
||||||
return "Module(name=" + name
|
return "Module(name=" + name
|
||||||
+ ", imports=[" + importJoiner + "]"
|
+ ", imports=[" + importJoiner + "]"
|
||||||
|
+ ", globals=[" + globalJoiner + "]"
|
||||||
+ ", functions=[" + funcJoiner + "])";
|
+ ", functions=[" + funcJoiner + "])";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,8 @@ public class StatementParserFactory {
|
|||||||
registry.put("if", new IfStatementParser());
|
registry.put("if", new IfStatementParser());
|
||||||
registry.put("loop", new LoopStatementParser());
|
registry.put("loop", new LoopStatementParser());
|
||||||
registry.put("return", new ReturnStatementParser());
|
registry.put("return", new ReturnStatementParser());
|
||||||
|
registry.put("break", new BreakStatementParser());
|
||||||
|
registry.put("continue",new ContinueStatementParser());
|
||||||
|
|
||||||
// 默认处理器: 表达式语句
|
// 默认处理器: 表达式语句
|
||||||
registry.put("", new ExpressionStatementParser());
|
registry.put("", new ExpressionStatementParser());
|
||||||
|
|||||||
@ -116,6 +116,7 @@ public class ASTPrinter {
|
|||||||
}
|
}
|
||||||
case ReturnNode r -> System.out.println(pad + "return" +
|
case ReturnNode r -> System.out.println(pad + "return" +
|
||||||
r.getExpression().map(e -> " " + e).orElse(""));
|
r.getExpression().map(e -> " " + e).orElse(""));
|
||||||
|
case BreakNode _ -> System.out.println(pad + "break");
|
||||||
case ExpressionStatementNode(ExpressionNode expression, NodeContext _) ->
|
case ExpressionStatementNode(ExpressionNode expression, NodeContext _) ->
|
||||||
System.out.println(pad + expression);
|
System.out.println(pad + expression);
|
||||||
case null, default -> System.out.println(pad + n); // 回退处理
|
case null, default -> System.out.println(pad + n); // 回退处理
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package org.jcnc.snow.compiler.parser.module;
|
package org.jcnc.snow.compiler.parser.module;
|
||||||
|
|
||||||
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.DeclarationNode;
|
||||||
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
|
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
|
||||||
import org.jcnc.snow.compiler.parser.ast.ImportNode;
|
import org.jcnc.snow.compiler.parser.ast.ImportNode;
|
||||||
import org.jcnc.snow.compiler.parser.ast.ModuleNode;
|
import org.jcnc.snow.compiler.parser.ast.ModuleNode;
|
||||||
@ -10,6 +11,7 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
|
|||||||
import org.jcnc.snow.compiler.parser.context.TokenStream;
|
import org.jcnc.snow.compiler.parser.context.TokenStream;
|
||||||
import org.jcnc.snow.compiler.parser.context.UnexpectedToken;
|
import org.jcnc.snow.compiler.parser.context.UnexpectedToken;
|
||||||
import org.jcnc.snow.compiler.parser.function.FunctionParser;
|
import org.jcnc.snow.compiler.parser.function.FunctionParser;
|
||||||
|
import org.jcnc.snow.compiler.parser.statement.DeclarationStatementParser;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -17,7 +19,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* {@code ModuleParser} 负责解析源码中的模块结构,是顶层结构解析器实现之一。
|
* {@code ModuleParser} 负责解析源码中的模块结构,是顶层结构解析器实现之一。
|
||||||
* <p>
|
* <p>
|
||||||
* 模块定义可包含多个导入(import)语句和函数定义(function),
|
* 模块定义可包含多个导入(import)语句、globals 全局声明和函数定义(function),
|
||||||
* 导入语句可在模块中任意位置出现,且允许模块体中穿插任意数量的空行(空行会被自动忽略,不影响语法结构)。
|
* 导入语句可在模块中任意位置出现,且允许模块体中穿插任意数量的空行(空行会被自动忽略,不影响语法结构)。
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
@ -26,6 +28,8 @@ import java.util.List;
|
|||||||
* <pre>
|
* <pre>
|
||||||
* module: mymod
|
* module: mymod
|
||||||
* import ...
|
* import ...
|
||||||
|
* globals:
|
||||||
|
* declare ...
|
||||||
* function ...
|
* function ...
|
||||||
* ...
|
* ...
|
||||||
* end module
|
* end module
|
||||||
@ -40,7 +44,7 @@ public class ModuleParser implements TopLevelParser {
|
|||||||
* 解析过程包括:
|
* 解析过程包括:
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li>匹配模块声明起始 {@code module: IDENTIFIER}。</li>
|
* <li>匹配模块声明起始 {@code module: IDENTIFIER}。</li>
|
||||||
* <li>收集模块体内所有 import 和 function 语句,允许穿插空行。</li>
|
* <li>收集模块体内所有 import、globals 和 function 语句,允许穿插空行。</li>
|
||||||
* <li>匹配模块结束 {@code end module}。</li>
|
* <li>匹配模块结束 {@code end module}。</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
* 若遇到未识别的语句,将抛出 {@link UnexpectedToken} 异常,定位错误位置和原因。
|
* 若遇到未识别的语句,将抛出 {@link UnexpectedToken} 异常,定位错误位置和原因。
|
||||||
@ -64,12 +68,15 @@ public class ModuleParser implements TopLevelParser {
|
|||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
List<ImportNode> imports = new ArrayList<>();
|
List<ImportNode> imports = new ArrayList<>();
|
||||||
|
List<DeclarationNode> globals = new ArrayList<>();
|
||||||
List<FunctionNode> functions = new ArrayList<>();
|
List<FunctionNode> functions = new ArrayList<>();
|
||||||
|
|
||||||
ImportParser importParser = new ImportParser();
|
ImportParser importParser = new ImportParser();
|
||||||
FunctionParser funcParser = new FunctionParser();
|
FunctionParser funcParser = new FunctionParser();
|
||||||
|
DeclarationStatementParser globalsParser = new DeclarationStatementParser();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// 跳过空行
|
||||||
if (ts.peek().getType() == TokenType.NEWLINE) {
|
if (ts.peek().getType() == TokenType.NEWLINE) {
|
||||||
ts.next();
|
ts.next();
|
||||||
continue;
|
continue;
|
||||||
@ -78,12 +85,33 @@ public class ModuleParser implements TopLevelParser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
String lex = ts.peek().getLexeme();
|
String lex = ts.peek().getLexeme();
|
||||||
if ("import".equals(lex)) {
|
switch (lex) {
|
||||||
imports.addAll(importParser.parse(ctx));
|
case "import" -> imports.addAll(importParser.parse(ctx));
|
||||||
} else if ("function".equals(lex)) {
|
case "function" -> functions.add(funcParser.parse(ctx));
|
||||||
functions.add(funcParser.parse(ctx));
|
case "globals" -> {
|
||||||
|
ts.expect("globals");
|
||||||
|
ts.expect(":");
|
||||||
|
ts.expectType(TokenType.NEWLINE);
|
||||||
|
while (true) {
|
||||||
|
if (ts.peek().getType() == TokenType.NEWLINE) {
|
||||||
|
ts.next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String innerLex = ts.peek().getLexeme();
|
||||||
|
if ("declare".equals(innerLex)) {
|
||||||
|
globals.add(globalsParser.parse(ctx));
|
||||||
|
} else if ("function".equals(innerLex) || "import".equals(innerLex) || "end".equals(innerLex)) {
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
throw new UnexpectedToken(
|
throw new UnexpectedToken(
|
||||||
|
"globals 区块中不支持的内容: " + innerLex,
|
||||||
|
ts.peek().getLine(),
|
||||||
|
ts.peek().getCol()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case null, default -> throw new UnexpectedToken(
|
||||||
"Unexpected token in module: " + lex,
|
"Unexpected token in module: " + lex,
|
||||||
ts.peek().getLine(),
|
ts.peek().getLine(),
|
||||||
ts.peek().getCol()
|
ts.peek().getCol()
|
||||||
@ -94,6 +122,6 @@ public class ModuleParser implements TopLevelParser {
|
|||||||
ts.expect("end");
|
ts.expect("end");
|
||||||
ts.expect("module");
|
ts.expect("module");
|
||||||
|
|
||||||
return new ModuleNode(name, imports, functions, new NodeContext(line, column, file));
|
return new ModuleNode(name, imports, globals, functions, new NodeContext(line, column, file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
package org.jcnc.snow.compiler.parser.statement;
|
||||||
|
|
||||||
|
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.BreakNode;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
||||||
|
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code BreakStatementParser} 用于解析 break 语句。
|
||||||
|
* <p>
|
||||||
|
* break 语句的语法仅包含关键字本身,随后以换行结束。
|
||||||
|
* 语义:立即终止当前(最内层)循环。
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class BreakStatementParser implements StatementParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 break 语句节点。
|
||||||
|
* <p>
|
||||||
|
* 期望格式为:'break' NEWLINE
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文
|
||||||
|
* @return BreakNode AST 节点
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public BreakNode parse(ParserContext ctx) {
|
||||||
|
// 记录当前位置作为 NodeContext
|
||||||
|
int line = ctx.getTokens().peek().getLine();
|
||||||
|
int column = ctx.getTokens().peek().getCol();
|
||||||
|
String file = ctx.getSourceName();
|
||||||
|
|
||||||
|
// 消耗 'break'
|
||||||
|
ctx.getTokens().expect("break");
|
||||||
|
// 行结束
|
||||||
|
ctx.getTokens().expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
|
return new BreakNode(new NodeContext(line, column, file));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package org.jcnc.snow.compiler.parser.statement;
|
||||||
|
|
||||||
|
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.ContinueNode;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
||||||
|
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code ContinueStatementParser} 用于解析 continue 语句。
|
||||||
|
* <p>
|
||||||
|
* continue 语句语法格式简单,仅包含关键字本身,随后以换行结束。
|
||||||
|
* 语义:跳过本次剩余循环体,继续执行 step → cond。
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class ContinueStatementParser implements StatementParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 continue 语句节点。
|
||||||
|
* <p>
|
||||||
|
* 期望格式为:'continue' NEWLINE
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文
|
||||||
|
* @return ContinueNode AST 节点
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ContinueNode parse(ParserContext ctx) {
|
||||||
|
// 记录当前位置作为 NodeContext
|
||||||
|
int line = ctx.getTokens().peek().getLine();
|
||||||
|
int column = ctx.getTokens().peek().getCol();
|
||||||
|
String file = ctx.getSourceName();
|
||||||
|
|
||||||
|
// 消耗 'continue'
|
||||||
|
ctx.getTokens().expect("continue");
|
||||||
|
// 行结束
|
||||||
|
ctx.getTokens().expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
|
return new ContinueNode(new NodeContext(line, column, file));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,7 +14,7 @@ import java.util.*;
|
|||||||
* 并可借助 {@code JSONParser.toJson(Object)} 方法将其序列化为 JSON 字符串,用于调试、
|
* 并可借助 {@code JSONParser.toJson(Object)} 方法将其序列化为 JSON 字符串,用于调试、
|
||||||
* 可视化或跨语言数据传输。
|
* 可视化或跨语言数据传输。
|
||||||
* <p>
|
* <p>
|
||||||
* 支持的节点类型包括(新增对 {@code BoolLiteralNode}、{@code UnaryExpressionNode} 的完整支持):
|
* 支持的节点类型包括:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link ModuleNode}</li>
|
* <li>{@link ModuleNode}</li>
|
||||||
* <li>{@link FunctionNode}</li>
|
* <li>{@link FunctionNode}</li>
|
||||||
@ -83,7 +83,7 @@ public class ASTJsonSerializer {
|
|||||||
return switch (n) {
|
return switch (n) {
|
||||||
// 模块节点
|
// 模块节点
|
||||||
case ModuleNode(
|
case ModuleNode(
|
||||||
String name, List<ImportNode> imports, List<FunctionNode> functions, NodeContext _
|
String name, List<ImportNode> imports, List<DeclarationNode> globals, List<FunctionNode> functions, NodeContext _
|
||||||
) -> {
|
) -> {
|
||||||
Map<String, Object> map = newNodeMap("Module");
|
Map<String, Object> map = newNodeMap("Module");
|
||||||
map.put("name", name);
|
map.put("name", name);
|
||||||
@ -92,6 +92,15 @@ public class ASTJsonSerializer {
|
|||||||
imps.add(Map.of("type", "Import", "module", imp.moduleName()));
|
imps.add(Map.of("type", "Import", "module", imp.moduleName()));
|
||||||
}
|
}
|
||||||
map.put("imports", imps);
|
map.put("imports", imps);
|
||||||
|
List<Object> globs = new ArrayList<>(globals.size());
|
||||||
|
for (DeclarationNode d : globals) {
|
||||||
|
Map<String, Object> decl = newNodeMap("Declaration");
|
||||||
|
decl.put("name", d.getName());
|
||||||
|
decl.put("varType", d.getType());
|
||||||
|
decl.put("init", d.getInitializer().map(ASTJsonSerializer::exprToMap).orElse(null));
|
||||||
|
globs.add(decl);
|
||||||
|
}
|
||||||
|
map.put("globals", globs);
|
||||||
List<Object> funcs = new ArrayList<>(functions.size());
|
List<Object> funcs = new ArrayList<>(functions.size());
|
||||||
for (FunctionNode f : functions) {
|
for (FunctionNode f : functions) {
|
||||||
funcs.add(nodeToMap(f));
|
funcs.add(nodeToMap(f));
|
||||||
|
|||||||
@ -5,50 +5,324 @@ import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode;
|
|||||||
import org.jcnc.snow.compiler.semantic.analyzers.base.ExpressionAnalyzer;
|
import org.jcnc.snow.compiler.semantic.analyzers.base.ExpressionAnalyzer;
|
||||||
import org.jcnc.snow.compiler.semantic.core.Context;
|
import org.jcnc.snow.compiler.semantic.core.Context;
|
||||||
import org.jcnc.snow.compiler.semantic.core.ModuleInfo;
|
import org.jcnc.snow.compiler.semantic.core.ModuleInfo;
|
||||||
|
import org.jcnc.snow.compiler.semantic.error.SemanticError;
|
||||||
import org.jcnc.snow.compiler.semantic.symbol.SymbolTable;
|
import org.jcnc.snow.compiler.semantic.symbol.SymbolTable;
|
||||||
import org.jcnc.snow.compiler.semantic.type.BuiltinType;
|
import org.jcnc.snow.compiler.semantic.type.BuiltinType;
|
||||||
import org.jcnc.snow.compiler.semantic.type.Type;
|
import org.jcnc.snow.compiler.semantic.type.Type;
|
||||||
|
|
||||||
|
import static org.jcnc.snow.compiler.semantic.type.BuiltinType.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code NumberLiteralAnalyzer} 用于对数字字面量表达式进行语义分析并推断其精确类型。
|
* {@code NumberLiteralAnalyzer}
|
||||||
* <p>
|
*
|
||||||
* 类型判定逻辑如下:
|
* <p>职责:
|
||||||
|
* <ul>
|
||||||
|
* <li>对数字字面量表达式进行语义分析,并推断其精确类型;</li>
|
||||||
|
* <li>按照推断类型进行范围校验;</li>
|
||||||
|
* <li>发生越界时,给出智能的错误提示与合理建议。</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>类型推断规则:</p>
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li>首先检查字面量末尾是否带有类型后缀(不区分大小写):
|
* <li>若字面量以类型后缀(b/s/l/f,大小写均可)结尾,则按后缀直接推断目标类型:</li>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@code b}: byte 类型({@link BuiltinType#BYTE})</li>
|
* <li>b → byte</li>
|
||||||
* <li>{@code s}: short 类型({@link BuiltinType#SHORT})</li>
|
* <li>s → short</li>
|
||||||
* <li>{@code l}: long 类型({@link BuiltinType#LONG})</li>
|
* <li>l → long</li>
|
||||||
* <li>{@code f}: float 类型({@link BuiltinType#FLOAT})</li>
|
* <li>f → float</li>
|
||||||
* <li>{@code d}: double 类型({@link BuiltinType#DOUBLE})</li>
|
|
||||||
* </ul>
|
* </ul>
|
||||||
* </li>
|
* <li>若无后缀,且文本包含小数点或科学计数法('.' 或 'e/E'),则推断为 double(浮点默认 double,不支持 d/D 后缀);</li>
|
||||||
* <li>若无后缀,则:
|
* <li>否则推断为 int。</li>
|
||||||
* <ul>
|
|
||||||
* <li>只要文本中包含 {@code '.'} 或 {@code e/E},即判为 double 类型</li>
|
|
||||||
* <li>否则默认判为 int 类型</li>
|
|
||||||
* </ul>
|
|
||||||
* </li>
|
|
||||||
* </ol>
|
* </ol>
|
||||||
* 本分析器不处理溢出、非法格式等诊断,仅做类型推断。
|
*
|
||||||
|
* <p>智能错误提示策略:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>整数:
|
||||||
|
* <ul>
|
||||||
|
* <li>int 放不下但 long 能放下 → 直接建议 long;</li>
|
||||||
|
* <li>连 long 也放不下 → 一次性提示“超出 int/long 可表示范围”。</li>
|
||||||
|
* </ul>
|
||||||
|
* </li>
|
||||||
|
* <li>浮点:
|
||||||
|
* <ul>
|
||||||
|
* <li>float 放不下但 double 能放下 → 直接建议 double(无需 d 后缀);</li>
|
||||||
|
* <li>连 double 也放不下 → 一次性提示“超出 float/double 可表示范围”。</li>
|
||||||
|
* </ul>
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class NumberLiteralAnalyzer implements ExpressionAnalyzer<NumberLiteralNode> {
|
public class NumberLiteralAnalyzer implements ExpressionAnalyzer<NumberLiteralNode> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对数字字面量进行语义分析,推断其类型。
|
* 根据字面量后缀和文本内容推断类型。
|
||||||
* <p>
|
|
||||||
* 分析流程:
|
|
||||||
* <ol>
|
|
||||||
* <li>若字面量以后缀结尾,直接按后缀映射类型。</li>
|
|
||||||
* <li>否则,若含有小数点或科学计数法标记,则为 double,否则为 int。</li>
|
|
||||||
* </ol>
|
|
||||||
*
|
*
|
||||||
* @param ctx 当前语义分析上下文(可用于记录诊断信息等,当前未使用)
|
* @param hasSuffix 是否存在类型后缀(仅 b/s/l/f 有效)
|
||||||
* @param mi 当前模块信息(未使用)
|
* @param suffix 后缀字符(已转小写)
|
||||||
* @param fn 当前函数节点(未使用)
|
* @param digits 去掉下划线与后缀后的数字主体(可能含 . 或 e/E)
|
||||||
* @param locals 当前作用域的符号表(未使用)
|
* @return 推断类型(byte / short / int / long / float / double 之一)
|
||||||
* @param expr 数字字面量表达式节点
|
*/
|
||||||
* @return 对应的 {@link BuiltinType},如 INT、DOUBLE 等
|
private static Type inferType(boolean hasSuffix, char suffix, String digits) {
|
||||||
|
if (hasSuffix) {
|
||||||
|
// 仅支持 b/s/l/f;不支持 d/D(浮点默认 double)
|
||||||
|
return switch (suffix) {
|
||||||
|
case 'b' -> BYTE;
|
||||||
|
case 's' -> SHORT;
|
||||||
|
case 'l' -> BuiltinType.LONG;
|
||||||
|
case 'f' -> BuiltinType.FLOAT;
|
||||||
|
default -> INT; // 其他后缀当作无效,按 int 处理(如需严格,可改为抛/报“非法后缀”)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 无后缀:包含小数点或 e/E → double;否则 int
|
||||||
|
if (looksLikeFloat(digits)) {
|
||||||
|
return BuiltinType.DOUBLE; // 浮点默认 double
|
||||||
|
}
|
||||||
|
return INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 做范围校验,发生越界时写入智能的错误与建议。
|
||||||
|
*
|
||||||
|
* @param ctx 语义上下文(承载错误列表与日志)
|
||||||
|
* @param node 当前数字字面量节点
|
||||||
|
* @param inferred 推断类型
|
||||||
|
* @param digits 规整后的数字主体(去下划线、去后缀、"123."→"123.0")
|
||||||
|
*/
|
||||||
|
private static void validateRange(Context ctx,
|
||||||
|
NumberLiteralNode node,
|
||||||
|
Type inferred,
|
||||||
|
String digits) {
|
||||||
|
try {
|
||||||
|
// —— 整数类型:不允许出现浮点形式 —— //
|
||||||
|
if (inferred == BYTE) {
|
||||||
|
if (looksLikeFloat(digits)) throw new NumberFormatException(digits);
|
||||||
|
Byte.parseByte(digits);
|
||||||
|
} else if (inferred == SHORT) {
|
||||||
|
if (looksLikeFloat(digits)) throw new NumberFormatException(digits);
|
||||||
|
Short.parseShort(digits);
|
||||||
|
} else if (inferred == INT) {
|
||||||
|
if (looksLikeFloat(digits)) throw new NumberFormatException(digits);
|
||||||
|
Integer.parseInt(digits);
|
||||||
|
} else if (inferred == BuiltinType.LONG) {
|
||||||
|
if (looksLikeFloat(digits)) throw new NumberFormatException(digits);
|
||||||
|
Long.parseLong(digits);
|
||||||
|
}
|
||||||
|
// —— 浮点类型:解析 + 上/下溢判断 —— //
|
||||||
|
else if (inferred == BuiltinType.FLOAT) {
|
||||||
|
float v = Float.parseFloat(digits);
|
||||||
|
// 上溢:Infinity;下溢:解析为 0.0 但文本并非“全零”
|
||||||
|
if (Float.isInfinite(v) || (v == 0.0f && isTextualZero(digits))) {
|
||||||
|
throw new NumberFormatException("float overflow/underflow: " + digits);
|
||||||
|
}
|
||||||
|
} else if (inferred == BuiltinType.DOUBLE) {
|
||||||
|
double v = Double.parseDouble(digits);
|
||||||
|
if (Double.isInfinite(v) || (v == 0.0 && isTextualZero(digits))) {
|
||||||
|
throw new NumberFormatException("double overflow/underflow: " + digits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
// 智能的错误描述与建议(header 使用 digits,避免带后缀)
|
||||||
|
String msg = getSmartSuggestionOneShot(digits, inferred);
|
||||||
|
ctx.getErrors().add(new SemanticError(node, msg));
|
||||||
|
ctx.log("错误: " + msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成智能的错误提示与建议。
|
||||||
|
*
|
||||||
|
* <p>策略:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>BYTE/SHORT/INT:若能放进更大整型,直接建议;否则一次性提示已超出 int/long 范围;</li>
|
||||||
|
* <li>LONG:直接提示“超出 long 可表示范围。”;</li>
|
||||||
|
* <li>FLOAT:若 double 能放下 → 建议 double;否则一次性提示“超出 float/double 可表示范围。”;</li>
|
||||||
|
* <li>DOUBLE:直接提示“超出 double 可表示范围。”。</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param digits 去后缀后的数字主体(用于 header 与建议示例)
|
||||||
|
* @param inferred 推断类型
|
||||||
|
* @return 完整错误消息(含建议)
|
||||||
|
*/
|
||||||
|
private static String getSmartSuggestionOneShot(String digits, Type inferred) {
|
||||||
|
String header;
|
||||||
|
String suggestion;
|
||||||
|
|
||||||
|
switch (inferred) {
|
||||||
|
case BYTE -> {
|
||||||
|
long v;
|
||||||
|
try {
|
||||||
|
v = Long.parseLong(digits);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// 连 long 都放不下:智能
|
||||||
|
header = composeHeader(digits, "超出 byte/short/int/long 可表示范围。");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
if (v >= Short.MIN_VALUE && v <= Short.MAX_VALUE) {
|
||||||
|
header = composeHeader(digits, "超出 byte 可表示范围。");
|
||||||
|
suggestion = "建议将变量类型声明为 short,并在数字末尾添加 's'(如 " + digits + "s)。";
|
||||||
|
} else if (v >= Integer.MIN_VALUE && v <= Integer.MAX_VALUE) {
|
||||||
|
header = composeHeader(digits, "超出 byte 可表示范围。");
|
||||||
|
suggestion = "建议将变量类型声明为 int(如 " + digits + ")。";
|
||||||
|
} else {
|
||||||
|
header = composeHeader(digits, "超出 byte 可表示范围。");
|
||||||
|
suggestion = "建议将变量类型声明为 long,并在数字末尾添加 'L'(如 " + digits + "L)。";
|
||||||
|
}
|
||||||
|
return appendSuggestion(header, suggestion);
|
||||||
|
}
|
||||||
|
case SHORT -> {
|
||||||
|
long v;
|
||||||
|
try {
|
||||||
|
v = Long.parseLong(digits);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
header = composeHeader(digits, "超出 short/int/long 可表示范围。");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
if (v >= Integer.MIN_VALUE && v <= Integer.MAX_VALUE) {
|
||||||
|
header = composeHeader(digits, "超出 short 可表示范围。");
|
||||||
|
suggestion = "建议将变量类型声明为 int(如 " + digits + ")。";
|
||||||
|
} else {
|
||||||
|
header = composeHeader(digits, "超出 short 可表示范围。");
|
||||||
|
suggestion = "建议将变量类型声明为 long,并在数字末尾添加 'L'(如 " + digits + "L)。";
|
||||||
|
}
|
||||||
|
return appendSuggestion(header, suggestion);
|
||||||
|
}
|
||||||
|
case INT -> {
|
||||||
|
try {
|
||||||
|
// 尝试解析为 long:若成功,说明“能进 long”
|
||||||
|
Long.parseLong(digits);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// 连 long 都放不下:智能
|
||||||
|
header = composeHeader(digits, "超出 int/long 可表示范围。");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
// 能进 long:直接建议 long
|
||||||
|
header = composeHeader(digits, "超出 int 可表示范围。");
|
||||||
|
suggestion = "建议将变量类型声明为 long,并在数字末尾添加 'L'(如 " + digits + "L)。";
|
||||||
|
return appendSuggestion(header, suggestion);
|
||||||
|
}
|
||||||
|
case LONG -> {
|
||||||
|
// 已明确处于 long 分支且越界:智能
|
||||||
|
header = composeHeader(digits, "超出 long 可表示范围。");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
case FLOAT -> {
|
||||||
|
// float 放不下:尝试 double,若能放下则直接建议 double;否则智能提示 float/double 都不行
|
||||||
|
boolean fitsDouble = fitsDouble(digits);
|
||||||
|
if (fitsDouble) {
|
||||||
|
header = composeHeader(digits, "超出 float 可表示范围。");
|
||||||
|
suggestion = "建议将变量类型声明为 double(如 " + digits + ")。"; // double 默认,无需 d 后缀
|
||||||
|
return appendSuggestion(header, suggestion);
|
||||||
|
} else {
|
||||||
|
header = composeHeader(digits, "超出 float/double 可表示范围。");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case DOUBLE -> {
|
||||||
|
header = composeHeader(digits, "超出 double 可表示范围。");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
header = composeHeader(digits, "超出 " + inferred + " 可表示范围。");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成越界错误头部:统一使用“数字主体”而非原始 raw(避免带后缀引起误导)。
|
||||||
|
*
|
||||||
|
* @param digits 去后缀后的数字主体
|
||||||
|
* @param tail 错误尾部描述(如“超出 int 可表示范围。”)
|
||||||
|
*/
|
||||||
|
private static String composeHeader(String digits, String tail) {
|
||||||
|
return "数值字面量越界: \"" + digits + "\" " + tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在头部后拼接建议文本(若存在)。
|
||||||
|
*
|
||||||
|
* @param header 错误头部
|
||||||
|
* @param suggestion 建议文本(可能为 null)
|
||||||
|
*/
|
||||||
|
private static String appendSuggestion(String header, String suggestion) {
|
||||||
|
return suggestion == null ? header : header + " " + suggestion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本层面判断“是否看起来是浮点字面量”:
|
||||||
|
* 只要包含 '.' 或 'e/E',即视为浮点。
|
||||||
|
*/
|
||||||
|
private static boolean looksLikeFloat(String s) {
|
||||||
|
return s.indexOf('.') >= 0 || s.indexOf('e') >= 0 || s.indexOf('E') >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本判断“是否为零”(不解析,纯文本):
|
||||||
|
* 在遇到 e/E 之前,若出现任意 '1'..'9',视为非零;否则视为零。
|
||||||
|
* 用于识别“文本非零但解析结果为 0.0”的下溢场景。
|
||||||
|
* <p>
|
||||||
|
* 例:
|
||||||
|
* "0.0" → true
|
||||||
|
* "000" → true
|
||||||
|
* "1e-9999" → false(e 前有 '1';若解析为 0.0 则视为下溢)
|
||||||
|
* "0e-9999" → true
|
||||||
|
*/
|
||||||
|
private static boolean isTextualZero(String s) {
|
||||||
|
if (s == null || s.isEmpty()) return false;
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
char c = s.charAt(i);
|
||||||
|
if (c == 'e' || c == 'E') break; // 指数部分不参与“是否为零”的判断
|
||||||
|
if (c >= '1' && c <= '9') return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断 double 是否能正常表示(不溢出、也非“文本非零但解析为 0.0”的下溢)。
|
||||||
|
*
|
||||||
|
* @param digits 去后缀后的数字主体
|
||||||
|
*/
|
||||||
|
private static boolean fitsDouble(String digits) {
|
||||||
|
try {
|
||||||
|
double d = Double.parseDouble(digits);
|
||||||
|
return !Double.isInfinite(d) && !(d == 0.0 && isTextualZero(digits));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规整数字串:
|
||||||
|
* 仅移除末尾的类型后缀(仅 b/s/l/f,大小写均可,不含 d/D)。
|
||||||
|
*
|
||||||
|
* @param s 原始字面量字符串
|
||||||
|
* @return 规整后的数字主体
|
||||||
|
*/
|
||||||
|
private static String normalizeDigits(String s) {
|
||||||
|
if (s == null) return "";
|
||||||
|
String t = s.trim();
|
||||||
|
if (t.isEmpty()) return t;
|
||||||
|
|
||||||
|
// 仅移除末尾的类型后缀(b/s/l/f,大小写均可)
|
||||||
|
char last = t.charAt(t.length() - 1);
|
||||||
|
if ("bBsSfFlL".indexOf(last) >= 0) {
|
||||||
|
t = t.substring(0, t.length() - 1).trim();
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 入口:对数字字面量进行语义分析。
|
||||||
|
* <p>
|
||||||
|
* 分步:
|
||||||
|
* <ol>
|
||||||
|
* <li>读取原始文本 raw;</li>
|
||||||
|
* <li>识别是否带后缀(仅 b/s/l/f);</li>
|
||||||
|
* <li>规整数字主体 digits(去下划线、去后缀、补小数点零);</li>
|
||||||
|
* <li>按规则推断目标类型;</li>
|
||||||
|
* <li>做范围校验,越界时记录智能的错误与建议;</li>
|
||||||
|
* <li>返回推断类型。</li>
|
||||||
|
* </ol>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Type analyze(Context ctx,
|
public Type analyze(Context ctx,
|
||||||
@ -57,41 +331,30 @@ public class NumberLiteralAnalyzer implements ExpressionAnalyzer<NumberLiteralNo
|
|||||||
SymbolTable locals,
|
SymbolTable locals,
|
||||||
NumberLiteralNode expr) {
|
NumberLiteralNode expr) {
|
||||||
|
|
||||||
// 获取字面量原始文本(如 "123", "3.14", "2f" 等)
|
// 1) 原始文本(如 "123", "3.14", "2f", "1_000_000L", "1e300")
|
||||||
String raw = expr.value();
|
String raw = expr.value();
|
||||||
if (raw == null || raw.isEmpty()) {
|
if (raw == null || raw.isEmpty()) {
|
||||||
// 理论上不应为空,兜底返回 int 类型
|
return INT; // 空文本回退为 int(按需可改为错误)
|
||||||
return BuiltinType.INT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取最后一个字符,判断是否为类型后缀(b/s/l/f/d,忽略大小写)
|
// 2) 是否带后缀(仅 b/s/l/f;不支持 d/D)
|
||||||
char lastChar = raw.charAt(raw.length() - 1);
|
char lastChar = raw.charAt(raw.length() - 1);
|
||||||
char suffix = Character.toLowerCase(lastChar);
|
char suffix = Character.toLowerCase(lastChar);
|
||||||
boolean hasSuffix = switch (suffix) {
|
boolean hasSuffix = switch (suffix) {
|
||||||
case 'b', 's', 'l', 'f', 'd' -> true;
|
case 'b', 's', 'l', 'f' -> true;
|
||||||
default -> false;
|
default -> false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 若有后缀,则 digits 为去除后缀的数字部分,否则为原文本
|
// 3) 规整数字主体
|
||||||
String digits = hasSuffix ? raw.substring(0, raw.length() - 1) : raw;
|
String digitsNormalized = normalizeDigits(raw);
|
||||||
|
|
||||||
// 1. 若有后缀,直接返回对应类型
|
// 4) 推断类型
|
||||||
if (hasSuffix) {
|
Type inferred = inferType(hasSuffix, suffix, digitsNormalized);
|
||||||
return switch (suffix) {
|
|
||||||
case 'b' -> BuiltinType.BYTE;
|
// 5) 范围校验(发生越界则收集智能的错误与建议)
|
||||||
case 's' -> BuiltinType.SHORT;
|
validateRange(ctx, expr, inferred, digitsNormalized);
|
||||||
case 'l' -> BuiltinType.LONG;
|
|
||||||
case 'f' -> BuiltinType.FLOAT;
|
return inferred;
|
||||||
case 'd' -> BuiltinType.DOUBLE;
|
|
||||||
default -> BuiltinType.INT; // 理论上不会到这里
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 无后缀,根据文本是否含小数点或科学计数法(e/E)判断类型
|
|
||||||
if (digits.indexOf('.') >= 0 || digits.indexOf('e') >= 0 || digits.indexOf('E') >= 0) {
|
|
||||||
return BuiltinType.DOUBLE; // 有小数/科学计数,默认 double 类型
|
|
||||||
}
|
|
||||||
|
|
||||||
return BuiltinType.INT; // 否则为纯整数,默认 int 类型
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,28 @@
|
|||||||
|
package org.jcnc.snow.compiler.semantic.analyzers.statement;
|
||||||
|
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.BreakNode;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
|
||||||
|
import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer;
|
||||||
|
import org.jcnc.snow.compiler.semantic.core.Context;
|
||||||
|
import org.jcnc.snow.compiler.semantic.core.ModuleInfo;
|
||||||
|
import org.jcnc.snow.compiler.semantic.symbol.SymbolTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code BreakAnalyzer} —— break 语句的语义分析器。
|
||||||
|
* <p>
|
||||||
|
* 目前不做额外检查;是否位于循环体内的限制由 IR 构建阶段(StatementBuilder)
|
||||||
|
* 进行安全校验(若出现在循环外,会抛出清晰的错误)。
|
||||||
|
* 如需在语义阶段提前报错,可在此处结合“循环上下文”进行校验。
|
||||||
|
*/
|
||||||
|
public class BreakAnalyzer implements StatementAnalyzer<BreakNode> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void analyze(Context ctx,
|
||||||
|
ModuleInfo mi,
|
||||||
|
FunctionNode fn,
|
||||||
|
SymbolTable locals,
|
||||||
|
BreakNode stmt) {
|
||||||
|
// no-op: break 本身不引入新符号或类型约束
|
||||||
|
// 在语义阶段校验“是否处于循环内”,需要在 ctx 或 SymbolTable 上增加上下文标记后在此检查。
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package org.jcnc.snow.compiler.semantic.analyzers.statement;
|
||||||
|
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.ContinueNode;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
|
||||||
|
import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer;
|
||||||
|
import org.jcnc.snow.compiler.semantic.core.Context;
|
||||||
|
import org.jcnc.snow.compiler.semantic.core.ModuleInfo;
|
||||||
|
import org.jcnc.snow.compiler.semantic.symbol.SymbolTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code ContinueAnalyzer} —— continue 语句的语义分析器。
|
||||||
|
* <p>
|
||||||
|
* 当前实现不做任何额外检查。continue 是否出现在有效的循环体内,
|
||||||
|
* 由 IR 构建阶段(如 StatementBuilder)负责判定与错误提示。
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 用于 AST 的 {@link ContinueNode} 语句节点。
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class ContinueAnalyzer implements StatementAnalyzer<ContinueNode> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分析 continue 语句节点的语义。
|
||||||
|
* <p>
|
||||||
|
* 该方法为 no-op,相关语义约束由后续阶段处理。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param ctx 语义分析上下文
|
||||||
|
* @param mi 当前模块信息
|
||||||
|
* @param fn 当前所在函数节点
|
||||||
|
* @param locals 当前作用域下的符号表
|
||||||
|
* @param stmt 需要分析的 continue 语句节点
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void analyze(Context ctx,
|
||||||
|
ModuleInfo mi,
|
||||||
|
FunctionNode fn,
|
||||||
|
SymbolTable locals,
|
||||||
|
ContinueNode stmt) {
|
||||||
|
// no-op: continue 语句的合法性由 IR 构建阶段检查
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -40,6 +40,8 @@ public final class AnalyzerRegistrar {
|
|||||||
registry.registerStatementAnalyzer(LoopNode.class, new LoopAnalyzer());
|
registry.registerStatementAnalyzer(LoopNode.class, new LoopAnalyzer());
|
||||||
registry.registerStatementAnalyzer(ReturnNode.class, new ReturnAnalyzer());
|
registry.registerStatementAnalyzer(ReturnNode.class, new ReturnAnalyzer());
|
||||||
registry.registerExpressionAnalyzer(BoolLiteralNode.class, new BoolLiteralAnalyzer());
|
registry.registerExpressionAnalyzer(BoolLiteralNode.class, new BoolLiteralAnalyzer());
|
||||||
|
registry.registerStatementAnalyzer(BreakNode.class, new BreakAnalyzer());
|
||||||
|
registry.registerStatementAnalyzer(ContinueNode.class, new ContinueAnalyzer());
|
||||||
|
|
||||||
// 特殊处理: 表达式语句(如 "foo();")作为语句包装表达式
|
// 特殊处理: 表达式语句(如 "foo();")作为语句包装表达式
|
||||||
registry.registerStatementAnalyzer(ExpressionStatementNode.class,
|
registry.registerStatementAnalyzer(ExpressionStatementNode.class,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.jcnc.snow.compiler.semantic.core;
|
|||||||
|
|
||||||
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
|
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
|
||||||
import org.jcnc.snow.compiler.parser.ast.ModuleNode;
|
import org.jcnc.snow.compiler.parser.ast.ModuleNode;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.DeclarationNode;
|
||||||
import org.jcnc.snow.compiler.parser.ast.ReturnNode;
|
import org.jcnc.snow.compiler.parser.ast.ReturnNode;
|
||||||
import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer;
|
import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer;
|
||||||
import org.jcnc.snow.compiler.semantic.error.SemanticError;
|
import org.jcnc.snow.compiler.semantic.error.SemanticError;
|
||||||
@ -54,11 +55,18 @@ public record FunctionChecker(Context ctx) {
|
|||||||
// 获取当前模块对应的语义信息
|
// 获取当前模块对应的语义信息
|
||||||
ModuleInfo mi = ctx.modules().get(mod.name());
|
ModuleInfo mi = ctx.modules().get(mod.name());
|
||||||
|
|
||||||
|
// 先构建全局符号表
|
||||||
|
SymbolTable globalScope = new SymbolTable(null);
|
||||||
|
for (DeclarationNode g : mod.globals()) {
|
||||||
|
var t = ctx.parseType(g.getType());
|
||||||
|
globalScope.define(new Symbol(g.getName(), t, SymbolKind.VARIABLE));
|
||||||
|
}
|
||||||
|
|
||||||
// 遍历模块中所有函数定义
|
// 遍历模块中所有函数定义
|
||||||
for (FunctionNode fn : mod.functions()) {
|
for (FunctionNode fn : mod.functions()) {
|
||||||
|
|
||||||
// 构建函数局部作用域符号表,设置父作用域为 null
|
// 构建函数局部作用域符号表,父作用域为 globalScope
|
||||||
SymbolTable locals = new SymbolTable(null);
|
SymbolTable locals = new SymbolTable(globalScope);
|
||||||
|
|
||||||
// 将函数参数注册为局部变量
|
// 将函数参数注册为局部变量
|
||||||
fn.parameters().forEach(p ->
|
fn.parameters().forEach(p ->
|
||||||
|
|||||||
@ -154,7 +154,7 @@ public final class CompileTask implements Task {
|
|||||||
String arg = args[i];
|
String arg = args[i];
|
||||||
switch (arg) {
|
switch (arg) {
|
||||||
case "run" -> runAfterCompile = true;
|
case "run" -> runAfterCompile = true;
|
||||||
case "-debug", "--debug" -> SnowConfig.MODE = Mode.DEBUG;
|
case "--debug" -> SnowConfig.MODE = Mode.DEBUG;
|
||||||
case "-o" -> {
|
case "-o" -> {
|
||||||
if (i + 1 < args.length) outputName = args[++i];
|
if (i + 1 < args.length) outputName = args[++i];
|
||||||
else {
|
else {
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
package org.jcnc.snow.vm.commands.flow.control;
|
package org.jcnc.snow.vm.commands.flow.control;
|
||||||
|
|
||||||
import org.jcnc.snow.vm.interfaces.Command;
|
import org.jcnc.snow.vm.interfaces.Command;
|
||||||
import org.jcnc.snow.vm.module.*;
|
import org.jcnc.snow.vm.module.CallStack;
|
||||||
|
import org.jcnc.snow.vm.module.LocalVariableStore;
|
||||||
|
import org.jcnc.snow.vm.module.OperandStack;
|
||||||
|
import org.jcnc.snow.vm.module.StackFrame;
|
||||||
|
import org.jcnc.snow.vm.utils.LoggingUtils;
|
||||||
|
|
||||||
import static org.jcnc.snow.common.SnowConfig.print;
|
import static org.jcnc.snow.common.SnowConfig.print;
|
||||||
|
|
||||||
@ -37,7 +41,7 @@ public class RetCommand implements Command {
|
|||||||
|
|
||||||
/* ----- Root frame: do NOT pop, just end program ----- */
|
/* ----- Root frame: do NOT pop, just end program ----- */
|
||||||
if (topFrame.getReturnAddress() == PROGRAM_END) {
|
if (topFrame.getReturnAddress() == PROGRAM_END) {
|
||||||
System.out.println("Return <root>");
|
LoggingUtils.logInfo("", "\nReturn <root>");
|
||||||
return PROGRAM_END; // VM main loop should break
|
return PROGRAM_END; // VM main loop should break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user