3. 解析多地址指令
任务目标
扩展单地址指令解析器,使其能够解析一条G代码行中出现的多个地址字(如 N10 G01 X10.5 Y-2.5 Z0 F300),并将每个地址字解析为独立的指令对象,按出现顺序输出。
实现方案
在词法层面将输入行按空白分割为序列,每个匹配 地址字母 + 数值 模式。解析器遍历序列,对每个调用地址解析函数,生成 Word 对象列表。数值支持整数、小数、正负号,不依赖正则表达式,使用手写状态机完成数值提取。
关键完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct {
char addr;
double value;
} Word;
// 手写数值解析:支持 12、-3.5、+0.25、.5 等格式
const char* parse_number(const char* p, double* out) {
double int_part = 0.0, frac_part = 0.0;
int sign = 1, has_digit = 0;
if (*p == '+' || *p == '-') {
if (*p == '-') sign = -1;
p++;
}
while (isdigit((unsigned char)*p)) {
int_part = int_part * 10.0 + (*p - '0');
has_digit = 1;
p++;
}
if (*p == '.') {
p++;
double scale = 0.1;
while (isdigit((unsigned char)*p)) {
frac_part += (*p - '0') * scale;
scale *= 0.1;
has_digit = 1;
p++;
}
}
if (!has_digit) return NULL; // 无有效数字
*out = sign * (int_part + frac_part);
return p;
}
// 解析单个地址字,成功返回1,失败返回0
int parse_word(const char* , Word* w) {
if (!isalpha((unsigned char)[0])) return 0;
w->addr = [0];
double val;
const char* end = parse_number( + 1, &val);
if (!end || *end != '\0') return 0; // 数值后还有多余字符
w->value = val;
return 1;
}
// 解析整行,返回解析成功的字数,-1表示行内有非法
int parse_line(const char* line, Word* words, int max_words) {
char buf[256];
strncpy(buf, line, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
int count = 0;
char* saveptr;
char* = strtok_r(buf, " \t\r\n", &saveptr);
while ( && count < max_words) {
if (!parse_word(, &words[count])) return -1;
count++;
= strtok_r(NULL, " \t\r\n", &saveptr);
}
return count;
}
int main(void) {
const char* test_line = "N10 G01 X10.5 Y-2.5 Z0 F300";
Word words[16];
int n = parse_line(test_line, words, 16);
if (n < 0) {
printf("解析失败:存在非法\n");
return 1;
}
for (int i = 0; i < n; i++) {
printf("%c %.4f\n", words[i].addr, words[i].value);
}
return 0;
}
编译与运行
gcc -o parser parser.c
./parser
验证方法
程序以硬编码测试行 N10 G01 X10.5 Y-2.5 Z0 F300 作为输入。编译运行后,观察标准输出是否依次打印6行:N 10.0000、G 1.0000、X 10.5000、Y -2.5000、Z 0.0000、F 300.0000。若输出与此顺序和数值一致,说明多地址解析正确。
边界行为说明
- 若某不是以字母开头(如
123),或字母后无有效数字(如X、Xabc),parse_line返回 -1,主程序报告解析失败。 - 地址字母大小写敏感,
x10与X10视为不同地址字。 - 数值解析器不依赖
strtod,可处理+.5、-0.25等格式;但指数形式(如1e3)不被支持,会判定为非法。