#include <stdio.h>
#include <string.h>
#include "text_parser.h"
#include "gcode_parser.h"
#define TEXT_TEST_1 \
"G21 G40 G17.1 G90\n" \
"(comment) G4 P0.5\n" \
"G04 X0.120 P7 I12.4 \r\n" \
"illegal line\n" \
"n0001 M3S 6000 \r\n" \
"(G2/G3) G002 X0.2 Y0.4 I1.1 J2.2 ;R1.5 (P1) \n" \
"N2 G00\tX+0 Y-0.0 F200.0\n" \
"\n" \
"G1 X+.01(cmnt1)Y+10.123 (cmnt2) ; Z -10\r\n" \
"\tX 100Y-100.000 (Z100\n" \
"M002 ; G0 X0 Y0"
int main() {
char *gcode_text = TEXT_TEST_1;
char *text = gcode_text;
char *line;
int line_size;
int line_num = 0;
int full_line_size;
gcode_line_data_t data;
printf("text size = %lu bytes\n\n", strlen(text));
while ( text && *text && (line = text_get_line(text, &line_size, &full_line_size)) ) {
// print line
printf("`");
text_print_line(line);
printf("` (%i bytes, #%i)\n", line_size, line_num++);
// parse line for gcodes
memset((char *)&data, 0, sizeof data);
if ( gcode_parse_line(line, &data) ) gcode_line_data_print(&data);
// go to next line
text += full_line_size;
}
return 0;
}
#ifndef GCODE_PARSER_H
#define GCODE_PARSER_H
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#define GCODE_DEBUG_PRINT 1
#define GCODE_TIME_BENCHMARK 1
#define GCODE_WORDS_SEARCH_S "NGXYZFIJKMTSHDPQRLEABCUVWO" \
"ngxyzfijkmtshdpqrleabcuvwo" \
"(;\r\n"
#define GCODE_COMMENT1_START_C '('
#define GCODE_COMMENT1_END_C ')'
#define GCODE_COMMENT2_START_C ';'
#define GCODE_RETURN_C '\r'
#define GCODE_NEWLINE_C '\n'
#define GCODE_G_CNT 100
#define GCODE_M_CNT 200
typedef struct {
uint32_t found; // found gcode words mask
uint8_t G[GCODE_G_CNT]; // found G codes masks
uint8_t M[GCODE_M_CNT]; // found M codes masks
// found other codes values (NXYZFIJKTSHDPQRLEABCUVWO)
float N; float X; float Y; float Z; float F; float I; float J; float K;
float T; float S; float H; float D; float P; float Q; float R; float L;
float E; float A; float B; float C; float U; float V; float W; float O;
} gcode_line_data_t;
//inline
int gcode_parse_line(char *line, gcode_line_data_t *data) {
char *fc;
char c;
float f;
int code;
int words_found = 0;
#if GCODE_TIME_BENCHMARK
clock_t begin;
clock_t end;
double time_spent;
static double time_spent_total = 0;
#endif
#if GCODE_TIME_BENCHMARK
begin = clock();
#endif
#define d (*data)
// search for gcode word chars
while ( line && *line && (fc = strpbrk(line, GCODE_WORDS_SEARCH_S)) ) {
// parse ';' comments and '\r','\n' chars
if ( *fc == GCODE_COMMENT2_START_C ||
*fc == GCODE_RETURN_C ||
*fc == GCODE_NEWLINE_C ) break;
// parse "(...)" comments
if ( *fc == GCODE_COMMENT1_START_C ) {
fc = strchr(fc, GCODE_COMMENT1_END_C);
if ( !fc ) break;
line = fc + 1;
continue;
}
// goto next char
line = fc+1;
// get gcode pair values (char+float)
if ( sscanf(fc, "%c%f", &c, &f) < 2 || c != *fc ) continue;
// gcode name to uppercase
if ( c >= 'a' && c <= 'z' ) c = 'A' + (c-'a');
// parse g code values
if ( c == 'G' ) { // G codes
code = (int)(10 * f);
if ( code >= 0 && code < (GCODE_G_CNT*10) ) {
d.found |= 1 << (c-'A');
d.G[code/10] |= 1 << (code%10);
words_found++;
}
} else if ( c == 'M' ) { // M codes
code = (int)(10 * f);
if ( code >= 0 && code < (GCODE_M_CNT*10) ) {
d.found |= 1 << (c-'A');
d.M[code/10] |= 1 << (code%10);
words_found++;
}
} else { // other codes - NXYZFIJKTSHDPQRLEABCUVWO
d.found |= 1 << (c-'A');
words_found++;
switch (c) {
case 'N': d.N = f; break;
case 'X': d.X = f; break;
case 'Y': d.Y = f; break;
case 'Z': d.Z = f; break;
case 'F': d.F = f; break;
case 'I': d.I = f; break;
case 'J': d.J = f; break;
case 'K': d.K = f; break;
case 'T': d.T = f; break;
case 'S': d.S = f; break;
case 'H': d.H = f; break;
case 'D': d.D = f; break;
case 'P': d.P = f; break;
case 'Q': d.Q = f; break;
case 'R': d.R = f; break;
case 'L': d.L = f; break;
case 'E': d.E = f; break;
case 'A': d.A = f; break;
case 'B': d.B = f; break;
case 'C': d.C = f; break;
case 'U': d.U = f; break;
case 'V': d.V = f; break;
case 'W': d.W = f; break;
case 'O': d.O = f; break;
}
}
}
#undef d
gcode_parse_end:
#if GCODE_TIME_BENCHMARK
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
time_spent_total += time_spent;
#if GCODE_DEBUG_PRINT >= 1
printf(" %f seconds (this line), %f seconds (all lines)\n",
time_spent, time_spent_total);
#endif
#endif
#if GCODE_DEBUG_PRINT >= 1
printf(" %i gcode words found\n", words_found);
#endif
return words_found;
}
//inline
int gcode_line_data_print(gcode_line_data_t *data) {
int c;
int sc;
if ( !data ) return -1;
#define d (*data)
if ( !d.found ) return 0;
// print G codes
if ( d.found & (1<<('G'-'A')) ) {
for ( c = 0; c < GCODE_G_CNT; c++ ) {
if ( !d.G[c] ) continue;
if ( d.G[c] == 1 ) { printf(" G%i\n", c); continue; }
for ( sc = 0; sc < 8; sc++ ) {
if ( d.G[c] & (1<<sc) ) printf(" G%i.%i\n", c, sc);
}
}
}
// print M codes
if ( d.found & (1<<('M'-'A')) ) {
for ( c = 0; c < GCODE_M_CNT; c++ ) {
if ( !d.M[c] ) continue;
if ( d.M[c] == 1 ) { printf(" M%i\n", c); continue; }
for ( sc = 0; sc < 8; sc++ ) {
if ( d.M[c] & (1<<sc) ) printf(" M%i.%i\n", c, sc);
}
}
}
// print other codes
if ( d.found & (1<<('N'-'A')) ) printf(" N%f\n", d.N);
if ( d.found & (1<<('X'-'A')) ) printf(" X%f\n", d.X);
if ( d.found & (1<<('Y'-'A')) ) printf(" Y%f\n", d.Y);
if ( d.found & (1<<('Z'-'A')) ) printf(" Z%f\n", d.Z);
if ( d.found & (1<<('F'-'A')) ) printf(" F%f\n", d.F);
if ( d.found & (1<<('I'-'A')) ) printf(" I%f\n", d.I);
if ( d.found & (1<<('J'-'A')) ) printf(" J%f\n", d.J);
if ( d.found & (1<<('K'-'A')) ) printf(" K%f\n", d.K);
if ( d.found & (1<<('T'-'A')) ) printf(" T%f\n", d.T);
if ( d.found & (1<<('S'-'A')) ) printf(" S%f\n", d.S);
if ( d.found & (1<<('H'-'A')) ) printf(" H%f\n", d.H);
if ( d.found & (1<<('D'-'A')) ) printf(" D%f\n", d.D);
if ( d.found & (1<<('P'-'A')) ) printf(" P%f\n", d.P);
if ( d.found & (1<<('Q'-'A')) ) printf(" Q%f\n", d.Q);
if ( d.found & (1<<('R'-'A')) ) printf(" R%f\n", d.R);
if ( d.found & (1<<('L'-'A')) ) printf(" L%f\n", d.L);
if ( d.found & (1<<('E'-'A')) ) printf(" E%f\n", d.E);
if ( d.found & (1<<('A'-'A')) ) printf(" A%f\n", d.A);
if ( d.found & (1<<('B'-'A')) ) printf(" B%f\n", d.B);
if ( d.found & (1<<('C'-'A')) ) printf(" C%f\n", d.C);
if ( d.found & (1<<('U'-'A')) ) printf(" U%f\n", d.U);
if ( d.found & (1<<('V'-'A')) ) printf(" V%f\n", d.V);
if ( d.found & (1<<('W'-'A')) ) printf(" W%f\n", d.W);
if ( d.found & (1<<('O'-'A')) ) printf(" O%f\n", d.O);
#undef d
return 0;
}
#endif
#ifndef TEXT_PARSER_H
#define TEXT_PARSER_H
#include <stdio.h>
#include <string.h>
#define TEXT_RETURN_C '\r'
#define TEXT_NEWLINE_C '\n'
#define TEXT_NEWLINE_PATTERN_S "\r\n"
#define TEXT_LINE_MAX_SIZE 256
//inline
char *text_get_line(char *text, int *line_size, int *full_line_size) {
char *new_line;
if ( !text || !*text ) goto line_not_found;
new_line = strpbrk(text, TEXT_NEWLINE_PATTERN_S);
if ( !new_line ) new_line = memchr(text, 0, TEXT_LINE_MAX_SIZE);
if ( !new_line ) goto line_not_found;
*line_size = (int) (new_line - text);
*full_line_size = *line_size + strspn(new_line, TEXT_NEWLINE_PATTERN_S);
return text;
line_not_found:
*line_size = 0;
*full_line_size = 0;
return NULL;
}
//inline
int text_print_line(char *line) {
int i;
if ( !line || !(*line) ) return 0;
for ( i = 0;
line[i] && line[i] != TEXT_RETURN_C && line[i] != TEXT_NEWLINE_C;
i++ ) printf("%c", line[i]);
return i;
}
#endif