提示词:

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

总结:
按 LinuxCNC read_g/read_m 的模态组规则,补充同一行同模态组 G/M 码冲突检查;新增 G0 G1 与 M3 M4 拒绝用例。已通过 ./test-native.sh 和 ./test-linuxcnc-source-link.sh。
This commit is contained in:
wangdequan
2026-05-23 17:59:24 +08:00
parent 575bcf24d8
commit f3f3a1dfa5
2 changed files with 203 additions and 0 deletions

View File

@@ -495,6 +495,187 @@ bool has_m_code(const std::vector<Word> &word_list, int code) {
return false;
}
int linuxcnc_g_code_number(double value) {
const double scaled = value * 10.0;
int code = static_cast<int>(std::floor(scaled));
const double fraction = scaled - static_cast<double>(code);
if (fraction > 0.999) {
code = static_cast<int>(std::ceil(scaled));
}
return code;
}
int supported_linuxcnc_g_modal_group(double value) {
const int code = linuxcnc_g_code_number(value);
switch (code) {
case 0:
case 10:
case 20:
case 30:
case 300:
case 500:
case 510:
case 520:
case 610:
case 620:
case 700:
case 710:
case 720:
case 730:
case 740:
case 760:
case 800:
case 810:
case 820:
case 830:
case 840:
case 850:
case 860:
case 870:
case 880:
case 890:
return 1;
case 170:
case 180:
case 190:
return 2;
case 900:
case 910:
return 3;
case 901:
case 911:
return 4;
case 930:
case 940:
case 950:
return 5;
case 200:
case 210:
case 7000:
case 7100:
return 6;
case 400:
case 410:
case 411:
case 420:
case 421:
return 7;
case 430:
case 431:
case 432:
case 434:
case 435:
case 490:
return 8;
case 980:
case 990:
return 10;
case 540:
case 550:
case 560:
case 570:
case 580:
case 590:
case 591:
case 592:
case 593:
return 12;
case 611:
case 640:
return 13;
case 960:
case 970:
return 14;
case 70:
case 80:
return 15;
case 922:
case 923:
return 16;
default:
return -1;
}
}
int supported_linuxcnc_m_modal_group(int value) {
if (value >= 100 && value <= 199) {
return 10;
}
switch (value) {
case 0:
case 1:
case 2:
case 30:
case 60:
case 99:
return 4;
case 62:
case 63:
case 64:
case 65:
case 66:
return 5;
case 6:
case 61:
return 6;
case 3:
case 4:
case 5:
case 19:
case 70:
case 71:
case 72:
case 73:
return 7;
case 7:
case 8:
case 9:
return 8;
case 48:
case 49:
case 50:
case 51:
case 52:
case 53:
return 9;
default:
return -1;
}
}
bool check_linuxcnc_modal_group_conflicts(const std::vector<Word> &word_list, std::string *error) {
std::array<bool, 17> g_modes{};
std::array<bool, 11> m_modes{};
for (const Word &word : word_list) {
if (word.letter == 'G') {
const int mode = supported_linuxcnc_g_modal_group(word.value);
if (mode < 0) {
continue;
}
if (g_modes[static_cast<size_t>(mode)]) {
if (error) {
*error = "Two G codes used from same modal group";
}
return false;
}
g_modes[static_cast<size_t>(mode)] = true;
} else if (word.letter == 'M') {
const int mode = supported_linuxcnc_m_modal_group(rounded_value(word.value));
if (mode < 0) {
continue;
}
if (m_modes[static_cast<size_t>(mode)]) {
if (error) {
*error = "Two M codes used from same modal group";
}
return false;
}
m_modes[static_cast<size_t>(mode)] = true;
}
}
return true;
}
std::string lower_compact(const std::string &value) {
std::string out;
out.reserve(value.size());
@@ -2927,6 +3108,9 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
if (!parse_word_list_strict(line, &word_list, error)) {
return -1;
}
if (!check_linuxcnc_modal_group_conflicts(word_list, error)) {
return -1;
}
refresh_readonly_named_parameters(line_number);
const std::string o_identifier = first_o_identifier(keyword_line, word_list);
const bool has_o_word = !o_identifier.empty();

View File

@@ -3572,6 +3572,25 @@ int main() {
sizeof(duplicate_axis_word_program) - 1) != 0,
"expected LinuxCNC to reject multiple X words on one line");
const char same_modal_group_g_program[] =
"G21 G90\n"
"F100\n"
"G0 G1 X1\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
same_modal_group_g_program,
sizeof(same_modal_group_g_program) - 1) != 0,
"expected LinuxCNC to reject two G codes from the same modal group");
const char same_modal_group_m_program[] =
"G21 G90\n"
"M3 M4\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
same_modal_group_m_program,
sizeof(same_modal_group_m_program) - 1) != 0,
"expected LinuxCNC to reject two M codes from the same modal group");
const char scientific_notation_word_program[] =
"G21 G90\n"
"F100\n"