├── BytecodeMachine.sln
├── BytecodeMachine
├── BytecodeMachine.vcxproj
├── BytecodeMachine.vcxproj.filters
├── BytecodeMachine.vcxproj.user
├── Command.cpp
├── Command.h
├── Error.cpp
├── Error.h
├── Main.cpp
├── Main.h
├── Stack.cpp
├── Stack.h
└── Value.h
├── LICENSE
└── README.md
/BytecodeMachine.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30204.135
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BytecodeMachine", "BytecodeMachine\BytecodeMachine.vcxproj", "{CBD5C594-C3A6-4755-915F-4E5A66F1830C}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {CBD5C594-C3A6-4755-915F-4E5A66F1830C}.Debug|x64.ActiveCfg = Debug|x64
17 | {CBD5C594-C3A6-4755-915F-4E5A66F1830C}.Debug|x64.Build.0 = Debug|x64
18 | {CBD5C594-C3A6-4755-915F-4E5A66F1830C}.Debug|x86.ActiveCfg = Debug|Win32
19 | {CBD5C594-C3A6-4755-915F-4E5A66F1830C}.Debug|x86.Build.0 = Debug|Win32
20 | {CBD5C594-C3A6-4755-915F-4E5A66F1830C}.Release|x64.ActiveCfg = Release|x64
21 | {CBD5C594-C3A6-4755-915F-4E5A66F1830C}.Release|x64.Build.0 = Release|x64
22 | {CBD5C594-C3A6-4755-915F-4E5A66F1830C}.Release|x86.ActiveCfg = Release|Win32
23 | {CBD5C594-C3A6-4755-915F-4E5A66F1830C}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {CEFED96C-F41F-4BD2-9AC7-609FBFC33D9B}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/BytecodeMachine/BytecodeMachine.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {cbd5c594-c3a6-4755-915f-4e5a66f1830c}
25 | BytecodeMachine
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | false
78 |
79 |
80 | true
81 |
82 |
83 | false
84 |
85 |
86 |
87 | Level3
88 | true
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Level3
100 | true
101 | true
102 | true
103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
104 | true
105 |
106 |
107 | Console
108 | true
109 | true
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | true
117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
118 | true
119 | /utf-8 %(AdditionalOptions)
120 |
121 |
122 | Console
123 | true
124 |
125 |
126 |
127 |
128 | Level3
129 | true
130 | true
131 | true
132 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
133 | true
134 | /utf-8 %(AdditionalOptions)
135 |
136 |
137 | Console
138 | true
139 | true
140 | true
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/BytecodeMachine/BytecodeMachine.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | 源文件
20 |
21 |
22 | 源文件
23 |
24 |
25 | 源文件
26 |
27 |
28 | 源文件
29 |
30 |
31 |
32 |
33 | 头文件
34 |
35 |
36 | 头文件
37 |
38 |
39 | 头文件
40 |
41 |
42 | 头文件
43 |
44 |
45 | 头文件
46 |
47 |
48 |
--------------------------------------------------------------------------------
/BytecodeMachine/BytecodeMachine.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WindowsLocalDebugger
7 |
8 |
9 |
10 |
11 | WindowsLocalDebugger
12 |
13 |
--------------------------------------------------------------------------------
/BytecodeMachine/Command.cpp:
--------------------------------------------------------------------------------
1 | #include "Command.h"
2 |
3 | void cmd_Push(const vector* params)
4 | {
5 | if (params->size() != 1)
6 | {
7 | Error("执行 PUSH 指令出错:" + params->size() ? "过多的参数" : "过少的参数");
8 | return;
9 | }
10 | PushValue((*params)[0]);
11 | }
12 |
13 | void cmd_Pop(const vector* params)
14 | {
15 | if (params->size())
16 | {
17 | Error("执行 POP 指令出错:过多的参数");
18 | return;
19 | }
20 | PopValue();
21 | }
22 |
23 | void cmd_Add(const vector* params)
24 | {
25 | if (params->size())
26 | {
27 | Error("执行 ADD 指令出错:过多的参数");
28 | return;
29 | }
30 | Value* value1 = GetValue(-1);
31 | Value* value2 = GetValue(-2);
32 | if (!(value1 && value2))
33 | {
34 | Error("执行 ADD 指令出错:获取栈内参数失败");
35 | return;
36 | }
37 | if (!(value1->type == TYPE_NUMBER && value2->type == TYPE_NUMBER))
38 | {
39 | Error("执行 ADD 指令出错:错误的算数类型");
40 | return;
41 | }
42 | Value resultValue = { TYPE_NUMBER, to_string(atof(value1->content.c_str()) + atof(value2->content.c_str())) };
43 | PopValue();
44 | PopValue();
45 | PushValue(resultValue);
46 | }
47 |
48 | void cmd_Sub(const vector* params)
49 | {
50 | if (params->size())
51 | {
52 | Error("执行 SUB 指令出错:过多的参数");
53 | return;
54 | }
55 | Value* value1 = GetValue(-1);
56 | Value* value2 = GetValue(-2);
57 | if (!(value1 && value2))
58 | {
59 | Error("执行 SUB 指令出错:获取栈内参数失败");
60 | return;
61 | }
62 | if (!(value1->type == TYPE_NUMBER && value2->type == TYPE_NUMBER))
63 | {
64 | Error("执行 SUB 指令出错:错误的算数类型");
65 | return;
66 | }
67 | Value resultValue = { TYPE_NUMBER, to_string(atof(value2->content.c_str()) - atof(value1->content.c_str())) };
68 | PopValue();
69 | PopValue();
70 | PushValue(resultValue);
71 | }
72 |
73 | void cmd_Mul(const vector* params)
74 | {
75 | if (params->size())
76 | {
77 | Error("执行 MUL 指令出错:过多的参数");
78 | return;
79 | }
80 | Value* value1 = GetValue(-1);
81 | Value* value2 = GetValue(-2);
82 | if (!(value1 && value2))
83 | {
84 | Error("执行 MUL 指令出错:获取栈内参数失败");
85 | return;
86 | }
87 | if (!(value1->type == TYPE_NUMBER && value2->type == TYPE_NUMBER))
88 | {
89 | Error("执行 MUL 指令出错:错误的算数类型");
90 | return;
91 | }
92 | Value resultValue = { TYPE_NUMBER, to_string(atof(value1->content.c_str()) * atof(value2->content.c_str())) };
93 | PopValue();
94 | PopValue();
95 | PushValue(resultValue);
96 | }
97 |
98 | void cmd_Div(const vector* params)
99 | {
100 | if (params->size())
101 | {
102 | Error("执行 DIV 指令出错:过多的参数");
103 | return;
104 | }
105 | Value* value1 = GetValue(-1);
106 | Value* value2 = GetValue(-2);
107 | if (!(value1 && value2))
108 | {
109 | Error("执行 DIV 指令出错:获取栈内参数失败");
110 | return;
111 | }
112 | if (!(value1->type == TYPE_NUMBER && value2->type == TYPE_NUMBER))
113 | {
114 | Error("执行 DIV 指令出错:错误的算数类型");
115 | return;
116 | }
117 | if (!atof(value1->content.c_str()))
118 | {
119 | Error("执行 DIV 指令出错:除数为0");
120 | return;
121 | }
122 | Value resultValue = { TYPE_NUMBER, to_string(atof(value2->content.c_str()) / atof(value1->content.c_str())) };
123 | PopValue();
124 | PopValue();
125 | PushValue(resultValue);
126 | }
127 |
128 | void cmd_Out(const vector* params)
129 | {
130 | if (params->size())
131 | {
132 | Error("执行 OUT 指令出错:过多的参数");
133 | return;
134 | }
135 | Value* value = GetValue(-1);
136 | if (!value)
137 | {
138 | Error("执行 OUT 指令出错:获取栈内参数失败");
139 | return;
140 | }
141 | cout << value->content << endl;
142 | }
143 |
--------------------------------------------------------------------------------
/BytecodeMachine/Command.h:
--------------------------------------------------------------------------------
1 | #ifndef _COMMAND_H_
2 | #define _COMMAND_H_
3 |
4 | #include "Value.h"
5 | #include "Stack.h"
6 |
7 | #include
8 | using namespace std;
9 |
10 | typedef void (*OptionHandler) (const vector*);
11 |
12 | struct Command
13 | {
14 | const char* option;
15 | OptionHandler handler;
16 | };
17 |
18 | void cmd_Add(const vector* params);
19 | void cmd_Sub(const vector* params);
20 | void cmd_Mul(const vector* params);
21 | void cmd_Div(const vector* params);
22 | void cmd_Push(const vector* params);
23 | void cmd_Pop(const vector* params);
24 | void cmd_Out(const vector* params);
25 |
26 | const Command CMD_LIST[] = {
27 | { "ADD", cmd_Add },
28 | { "SUB", cmd_Sub },
29 | { "MUL", cmd_Mul },
30 | { "DIV", cmd_Div },
31 | { "PUSH", cmd_Push },
32 | { "POP", cmd_Pop },
33 | { "OUT", cmd_Out },
34 | };
35 |
36 | #endif // !_COMMAND_H_
37 |
38 |
--------------------------------------------------------------------------------
/BytecodeMachine/Error.cpp:
--------------------------------------------------------------------------------
1 | #include "Error.h"
2 |
3 | void Error(string info)
4 | {
5 | cout << "[Error:" << indexLine << "] " << info << endl;
6 |
7 | HasError = true;
8 | }
--------------------------------------------------------------------------------
/BytecodeMachine/Error.h:
--------------------------------------------------------------------------------
1 | #ifndef _ERROR_H_
2 | #define _ERROR_H_
3 |
4 | #include "Value.h"
5 |
6 | #include
7 | using namespace std;
8 |
9 | extern bool HasError;
10 |
11 | extern int indexLine;
12 |
13 | void Error(string info);
14 |
15 | #endif // !_ERROR_H_
16 |
--------------------------------------------------------------------------------
/BytecodeMachine/Main.cpp:
--------------------------------------------------------------------------------
1 | #include "Main.h"
2 |
3 | int indexLine = 1;
4 |
5 | bool HasError = false;
6 |
7 | vector _stack;
8 |
9 | int main(int argc, char** argv)
10 | {
11 | SetConsoleOutputCP(65001);
12 |
13 | string strLine;
14 | if (argc > 1)
15 | {
16 | ifstream inputFile(argv[1]);
17 | while (getline(inputFile, strLine))
18 | {
19 | if (!strLine.empty() && strLine[0] != ';')
20 | {
21 | string option;
22 | vector params;
23 | FormatCMD(strLine, option, ¶ms);
24 | HandleCMD(option, ¶ms);
25 | }
26 |
27 | if (HasError)
28 | break;
29 |
30 | indexLine++;
31 | }
32 | }
33 | else
34 | {
35 | while (!HasError)
36 | {
37 | cout << ">> ";
38 | getline(cin, strLine);
39 | if (!strLine.empty() && strLine[0] != ';')
40 | {
41 | string option;
42 | vector params;
43 | FormatCMD(strLine, option, ¶ms);
44 | HandleCMD(option, ¶ms);
45 | }
46 |
47 | indexLine++;
48 | }
49 | }
50 |
51 | return 0;
52 | }
53 |
54 | void FormatCMD(string strLine, string& option, vector* params)
55 | {
56 | string raw_params;
57 | if (strLine.find_first_of(' ') == string::npos)
58 | {
59 | option = strLine;
60 | }
61 | else
62 | {
63 | option = strLine.substr(0, strLine.find_first_of(' '));
64 | raw_params = strLine.substr(strLine.find_first_of(' '));
65 | }
66 |
67 | if (!raw_params.empty())
68 | {
69 | string::size_type pos1 = 0, pos2 = raw_params.find(',');
70 | while (string::npos != pos2)
71 | {
72 | string temp = raw_params.substr(pos1, pos2 - pos1);
73 | temp.erase(0, temp.find_first_not_of(" "));
74 | if (!temp.empty())
75 | params->push_back(temp);
76 |
77 | pos1 = pos2 + 1;
78 | pos2 = raw_params.find(',', pos1);
79 | }
80 | if (pos1 != raw_params.length())
81 | {
82 | string temp = raw_params.substr(pos1);
83 | temp.erase(0, temp.find_first_not_of(" "));
84 | if (!temp.empty())
85 | params->push_back(temp);
86 | }
87 | }
88 | }
89 |
90 | void HandleCMD(string option, vector* params)
91 | {
92 | OptionHandler handler = nullptr;
93 | for (auto cmd : CMD_LIST)
94 | {
95 | if (cmd.option == option)
96 | {
97 | handler = cmd.handler;
98 | break;
99 | }
100 | }
101 | if (handler)
102 | {
103 | vector values;
104 | for (auto param : *params)
105 | {
106 | Value value;
107 |
108 | if (param[0] == '\"' && param[param.size() - 1] == '\"')
109 | {
110 | value = { TYPE_STRING, param.substr(1, param.size() - 2) };
111 | }
112 | else if (param == "true" || param == "false" || param == "null")
113 | {
114 | value = { param == "null" ? TYPE_NULL : TYPE_BOOLEAN, param };
115 | }
116 | else
117 | {
118 | bool isAllNumber = true;
119 | for (size_t i = 0; i < param.size(); i++)
120 | {
121 | if (i == 0 && (param[i] == '+' || param[i] == '-'))
122 | {
123 | continue;
124 | }
125 | if (!(param[i] >= '0' && param[i] <= '9'))
126 | {
127 | isAllNumber = false;
128 | break;
129 | }
130 | }
131 | if (isAllNumber)
132 | value = { TYPE_NUMBER, param };
133 | else
134 | {
135 | Error("未知类型值:" + param);
136 | return;
137 | }
138 | }
139 |
140 | values.push_back(value);
141 | }
142 | handler(&values);
143 | }
144 | else
145 | Error("未知指令:" + option);
146 | }
--------------------------------------------------------------------------------
/BytecodeMachine/Main.h:
--------------------------------------------------------------------------------
1 | #ifndef _MAIN_H_
2 | #define _MAIN_H_
3 |
4 | #include "Value.h"
5 | #include "Error.h"
6 | #include "Stack.h"
7 | #include "Command.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | using namespace std;
15 |
16 | #include
17 |
18 | void FormatCMD(string strLine, string& option, vector* params);
19 |
20 | void HandleCMD(string option, vector* params);
21 |
22 | #endif // !_MAIN_H_
23 |
24 |
--------------------------------------------------------------------------------
/BytecodeMachine/Stack.cpp:
--------------------------------------------------------------------------------
1 | #include "Stack.h"
2 |
3 | Value* GetValue(int index)
4 | {
5 | int validIndex = index >= 0 ? index : _stack.size() + index;
6 |
7 | if (validIndex >= 0 && validIndex < _stack.size())
8 | return &_stack[validIndex];
9 |
10 | Error("尝试获取栈索引:"+ to_string(index) + " 时出错");
11 | return nullptr;
12 | }
13 |
14 | int PushValue(Value value)
15 | {
16 | _stack.push_back(value);
17 | return _stack.size() - 1;
18 | }
19 |
20 | int PopValue()
21 | {
22 | _stack.size() > 0 ? _stack.pop_back() : Error("尝试弹出栈顶元素时出错");
23 |
24 | return _stack.size() - 1;
25 | }
--------------------------------------------------------------------------------
/BytecodeMachine/Stack.h:
--------------------------------------------------------------------------------
1 | #ifndef _STACK_H_
2 | #define _STACK_H_
3 |
4 | #include "Error.h"
5 | #include "Value.h"
6 |
7 | #include
8 | using namespace std;
9 |
10 | extern vector _stack;
11 |
12 | Value* GetValue(int index);
13 |
14 | int PushValue(Value value);
15 |
16 | int PopValue();
17 |
18 | #endif // !_STACK_H_
19 |
20 |
--------------------------------------------------------------------------------
/BytecodeMachine/Value.h:
--------------------------------------------------------------------------------
1 | #ifndef _VALUE_H_
2 | #define _VALUE_H_
3 |
4 | #include
5 | using namespace std;
6 |
7 | enum ValueType
8 | {
9 | TYPE_NULL,
10 | TYPE_BOOLEAN,
11 | TYPE_NUMBER,
12 | TYPE_STRING,
13 | };
14 |
15 | struct Value
16 | {
17 | ValueType type;
18 | string content;
19 | };
20 |
21 | #endif // !_VALUE_H_
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Voidmatrix
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BytecodeMachine
2 |
3 | [](https://github.com/VoidmatrixHeathcliff/BytecodeMachine/stargazers) [](https://github.com/VoidmatrixHeathcliff/BytecodeMachine/network/members) [](https://github.com/VoidmatrixHeathcliff/BytecodeMachine/issues) 
4 |
5 | > 关于我用一天时间编写字节码解释引擎这件事……
6 |
7 | 这是一个基于栈的字节码解释引擎,使用汇编语言风格
8 |
9 | 实际生产环境意义不大,因为并没有对其性能进行测试,大概也仅仅是说可以跑起来的叭
10 |
11 | 配合编译器前端可以成为一门全新的编程语言(但是前端谁给我写呢?)
12 |
13 | 可能有学习的价值~
14 |
15 | + 支持通过命令参数从文件加载
16 | + 支持交互式命令环境
17 |
18 |
19 |
--------------------------------------------------------------------------------