@@ -58,6 +58,8 @@ export namespace gerber {
58
58
}
59
59
};
60
60
61
+ // G-codes
62
+
61
63
class G01 : public Command {
62
64
public:
63
65
std::string getNodeName () const override {
@@ -169,6 +171,106 @@ export namespace gerber {
169
171
}
170
172
};
171
173
174
+ // Properties
175
+
176
+ class Zeros {
177
+ public:
178
+ enum Enum : uint8_t {
179
+ SKIP_LEADING,
180
+ SKIP_TRAILING
181
+ };
182
+
183
+ Enum value;
184
+
185
+ private:
186
+ Zeros () = delete ;
187
+
188
+ public:
189
+ Zeros (Enum value) :
190
+ value (value) {}
191
+
192
+ static Enum from_string (const std::string_view& str) {
193
+ if (str == " L" ) {
194
+ return Enum::SKIP_LEADING;
195
+ } else if (str == " T" ) {
196
+ return Enum::SKIP_TRAILING;
197
+ }
198
+ throw std::invalid_argument (" Invalid zeros" );
199
+ }
200
+
201
+ bool operator ==(const Zeros& other) const {
202
+ return value == other.value ;
203
+ }
204
+
205
+ bool operator ==(const Enum& other) const {
206
+ return value == other;
207
+ }
208
+ };
209
+
210
+ class CoordinateNotation {
211
+ public:
212
+ enum Enum : uint8_t {
213
+ ABSOLUTE,
214
+ INCREMENTAL
215
+ };
216
+
217
+ Enum value;
218
+
219
+ private:
220
+ CoordinateNotation () = delete ;
221
+
222
+ public:
223
+ CoordinateNotation (Enum value) :
224
+ value (value) {}
225
+
226
+ static CoordinateNotation from_string (const std::string_view& str) {
227
+ if (str == " A" ) {
228
+ return Enum::ABSOLUTE;
229
+ } else if (str == " I" ) {
230
+ return Enum::INCREMENTAL;
231
+ }
232
+ throw std::invalid_argument (" Invalid coordinate notation" );
233
+ }
234
+
235
+ bool operator ==(const CoordinateNotation& other) const {
236
+ return value == other.value ;
237
+ }
238
+
239
+ bool operator ==(const Enum& other) const {
240
+ return value == other;
241
+ }
242
+ };
243
+
244
+ class FS : public ExtendedCommand {
245
+ public:
246
+ Zeros zeros;
247
+ CoordinateNotation coordinate_mode;
248
+
249
+ int x_integral;
250
+ int x_decimal;
251
+
252
+ int y_integral;
253
+ int y_decimal;
254
+
255
+ public:
256
+ FS (const std::string_view& zeros,
257
+ const std::string_view& coordinate_mode,
258
+ int x_integral,
259
+ int x_decimal,
260
+ int y_integral,
261
+ int y_decimal) :
262
+ zeros (Zeros::from_string(zeros)),
263
+ coordinate_mode (CoordinateNotation::from_string(coordinate_mode)),
264
+ x_integral (x_integral),
265
+ x_decimal (x_decimal),
266
+ y_integral (y_integral),
267
+ y_decimal (y_decimal) {}
268
+
269
+ std::string getNodeName () const override {
270
+ return " FS" ;
271
+ }
272
+ };
273
+
172
274
class SyntaxError : public std ::runtime_error {
173
275
public:
174
276
explicit SyntaxError (const std::string& message) :
@@ -181,15 +283,19 @@ export namespace gerber {
181
283
std::string_view full_source;
182
284
location_t global_index;
183
285
// Regular expressions cache
286
+ // G-codes
184
287
std::regex g_code_regex;
185
288
std::regex g04_regex;
289
+ // Properties
290
+ std::regex fs_regex;
186
291
187
292
Parser () :
188
293
commands (0 ),
189
294
full_source (" " ),
190
295
global_index (0 ),
191
296
g_code_regex (" ^[Gg]0*([1-9][0-9]*)\\ *" ),
192
- g04_regex (" ^[Gg]0*4([^%*]+)\\ *" ) {}
297
+ g04_regex (" ^[Gg]0*4([^%*]+)\\ *" ),
298
+ fs_regex (" ^%FS([TL])([IA])X([0-9])([0-9])Y([0-9])([0-9])\\ *%" ) {}
193
299
194
300
~Parser () {}
195
301
@@ -205,14 +311,17 @@ export namespace gerber {
205
311
global_index = 0 ;
206
312
207
313
while (global_index < (full_source.size () - 1 )) {
208
- global_index += parse_global (source , global_index);
314
+ global_index += parse_global (full_source , global_index);
209
315
}
210
316
211
317
return File (std::move (commands));
212
318
}
213
319
214
320
location_t parse_global (const std::string_view& source, const location_t & index) {
215
321
const std::string_view sub_source{source.begin () + index, source.end ()};
322
+ if (sub_source.empty ()) {
323
+ return 0 ;
324
+ }
216
325
217
326
switch (sub_source[0 ]) {
218
327
case ' G' :
@@ -225,6 +334,10 @@ export namespace gerber {
225
334
return 1 ;
226
335
break ;
227
336
337
+ case ' %' :
338
+ return parse_extended_command (sub_source, index);
339
+ break ;
340
+
228
341
default :
229
342
break ;
230
343
}
@@ -324,5 +437,50 @@ export namespace gerber {
324
437
325
438
throw_syntax_error ();
326
439
}
440
+
441
+ offset_t parse_extended_command (const std::string_view& source, const location_t & index) {
442
+ // Shortest possible extended command is probably %TD*%, so 5 chars at least.
443
+ if (source.length () < 5 ) {
444
+ throw_syntax_error ();
445
+ }
446
+
447
+ switch (source[1 ]) {
448
+ case ' F' :
449
+ return parse_fs_command (source, index);
450
+ break ;
451
+
452
+ default :
453
+ break ;
454
+ }
455
+
456
+ throw_syntax_error ();
457
+ }
458
+
459
+ offset_t parse_fs_command (const std::string_view& source, const location_t & index) {
460
+ if (source.length () < 13 ) {
461
+ throw_syntax_error ();
462
+ }
463
+ std::cmatch match;
464
+
465
+ const auto result = std::regex_search (
466
+ source.data (),
467
+ source.data () + source.size (),
468
+ match,
469
+ fs_regex,
470
+ std::regex_constants::match_continuous
471
+ );
472
+ if (result && match.size () == 7 ) {
473
+ commands.push_back (std::make_shared<FS>(
474
+ match[1 ].str (),
475
+ match[2 ].str (),
476
+ std::stoi (match[3 ].str ()),
477
+ std::stoi (match[4 ].str ()),
478
+ std::stoi (match[5 ].str ()),
479
+ std::stoi (match[6 ].str ())
480
+ ));
481
+ return match.length ();
482
+ }
483
+ throw_syntax_error ();
484
+ }
327
485
};
328
486
} // namespace gerber
0 commit comments