提示词:

对标 LinuxCNC,分阶段完善 Web 版数控系统仿真的 WASM 程序,继续补齐 G 代码语法并严格测试。

总结:
- 对齐 LinuxCNC 对同一行重复非 G/M 字的拒绝行为,覆盖 G1 X1 X2 等重复轴字错误。
- 将 smoke parser 字母字归一为大写,补充 lowercase 普通字和命名 O-word 回归覆盖。
- 已通过 ./test-native.sh 和 ./test-linuxcnc-source-link.sh。
This commit is contained in:
wangdequan
2026-05-23 17:50:37 +08:00
parent 3333ddb373
commit 575bcf24d8
2 changed files with 77 additions and 1 deletions

View File

@@ -354,13 +354,14 @@ bool looks_like_real_start(char ch) {
bool parse_word_list_impl(const std::string &line, std::vector<Word> *words, std::string *error, bool strict) { bool parse_word_list_impl(const std::string &line, std::vector<Word> *words, std::string *error, bool strict) {
words->clear(); words->clear();
std::array<bool, 26> seen_letters{};
const char *text = line.c_str(); const char *text = line.c_str();
for (size_t i = 0; text[i] != '\0';) { for (size_t i = 0; text[i] != '\0';) {
if (std::isspace(static_cast<unsigned char>(text[i]))) { if (std::isspace(static_cast<unsigned char>(text[i]))) {
++i; ++i;
continue; continue;
} }
char letter = text[i]; char letter = static_cast<char>(std::toupper(static_cast<unsigned char>(text[i])));
if (!std::isalpha(static_cast<unsigned char>(letter))) { if (!std::isalpha(static_cast<unsigned char>(letter))) {
++i; ++i;
continue; continue;
@@ -391,6 +392,16 @@ bool parse_word_list_impl(const std::string &line, std::vector<Word> *words, std
} }
return false; return false;
} }
if (letter != 'G' && letter != 'M') {
const size_t letter_index = static_cast<size_t>(letter - 'A');
if (strict && seen_letters[letter_index]) {
if (error) {
*error = "multiple " + std::string(1, letter) + " words on one line";
}
return false;
}
seen_letters[letter_index] = true;
}
words->push_back({letter, value}); words->push_back({letter, value});
i = next; i = next;
} }

View File

@@ -242,6 +242,8 @@ int main() {
bool saw_global_low_parameter_after_oword = false; bool saw_global_low_parameter_after_oword = false;
bool saw_named_oword_call = false; bool saw_named_oword_call = false;
bool saw_named_oword_return = false; bool saw_named_oword_return = false;
bool saw_lowercase_named_oword_call = false;
bool saw_lowercase_named_oword_return = false;
bool saw_named_parameter_reference = false; bool saw_named_parameter_reference = false;
bool saw_named_parameter_call_arg = false; bool saw_named_parameter_call_arg = false;
bool saw_named_parameter_local = false; bool saw_named_parameter_local = false;
@@ -274,6 +276,7 @@ int main() {
bool saw_word_unary_function_motion = false; bool saw_word_unary_function_motion = false;
bool saw_word_atan_function_motion = false; bool saw_word_atan_function_motion = false;
bool saw_signed_word_unary_function_motion = false; bool saw_signed_word_unary_function_motion = false;
bool saw_lowercase_motion = false;
bool saw_trig_function_motion = false; bool saw_trig_function_motion = false;
bool saw_inverse_trig_function_motion = false; bool saw_inverse_trig_function_motion = false;
bool saw_atan_function_motion = false; bool saw_atan_function_motion = false;
@@ -3030,6 +3033,41 @@ int main() {
ok &= expect(saw_named_oword_call, "expected named O-word subprogram call"); ok &= expect(saw_named_oword_call, "expected named O-word subprogram call");
ok &= expect(saw_named_oword_return, "expected named O-word return to caller"); ok &= expect(saw_named_oword_return, "expected named O-word return to caller");
const char lowercase_named_oword_subprogram[] =
"g21 g90\n"
"g0 x0 y0 z0\n"
"f100\n"
"o<lower_named> call [5]\n"
"g1 y3\n"
"m30\n"
"o<lower_named> sub\n"
"g1 x#1\n"
"o<lower_named> return\n"
"g1 x99\n"
"o<lower_named> endsub\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
lowercase_named_oword_subprogram,
sizeof(lowercase_named_oword_subprogram) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_lowercase_named_oword_call = saw_lowercase_named_oword_call ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 8 &&
event.end.x == 5.0);
saw_lowercase_named_oword_return = saw_lowercase_named_oword_return ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 5 &&
event.start.x == 5.0 &&
event.end.y == 3.0);
ok &= expect(!(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 10 &&
event.end.x == 99.0),
"expected lowercase named O-word return to skip remaining subprogram body");
}
ok &= expect(saw_lowercase_named_oword_call, "expected lowercase named O-word subprogram call");
ok &= expect(saw_lowercase_named_oword_return, "expected lowercase named O-word return to caller");
const char named_parameter_program[] = const char named_parameter_program[] =
"#<target> = 5\n" "#<target> = 5\n"
"#<step> = [#<target> + 2]\n" "#<step> = [#<target> + 2]\n"
@@ -3524,6 +3562,16 @@ int main() {
sizeof(g1_without_feed_program) - 1) != 0, sizeof(g1_without_feed_program) - 1) != 0,
"expected LinuxCNC to reject G1 with zero feed rate"); "expected LinuxCNC to reject G1 with zero feed rate");
const char duplicate_axis_word_program[] =
"G21 G90\n"
"F100\n"
"G1 X1 X2\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
duplicate_axis_word_program,
sizeof(duplicate_axis_word_program) - 1) != 0,
"expected LinuxCNC to reject multiple X words on one line");
const char scientific_notation_word_program[] = const char scientific_notation_word_program[] =
"G21 G90\n" "G21 G90\n"
"F100\n" "F100\n"
@@ -3597,6 +3645,23 @@ int main() {
ok &= expect(saw_word_atan_function_motion, "expected LinuxCNC ATAN function as a word value"); ok &= expect(saw_word_atan_function_motion, "expected LinuxCNC ATAN function as a word value");
ok &= expect(saw_signed_word_unary_function_motion, "expected signed LinuxCNC unary function as a word value"); ok &= expect(saw_signed_word_unary_function_motion, "expected signed LinuxCNC unary function as a word value");
const char lowercase_word_program[] =
"g21 g90\n"
"f100\n"
"g1 x3\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
lowercase_word_program,
sizeof(lowercase_word_program) - 1) == 0,
cnc_sim_last_error(sim));
for (const auto &event : events) {
saw_lowercase_motion = saw_lowercase_motion ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 3 &&
event.end.x == 3.0);
}
ok &= expect(saw_lowercase_motion, "expected LinuxCNC lowercase word parsing");
const char additional_math_function_program[] = const char additional_math_function_program[] =
"#1 = [ASIN[0.5] + ACOS[0.5]]\n" "#1 = [ASIN[0.5] + ACOS[0.5]]\n"
"#2 = [FIX[1.9] + FUP[1.1] + ROUND[-1.5]]\n" "#2 = [FIX[1.9] + FUP[1.1] + ROUND[-1.5]]\n"