4 code for parsing calibration file, generated by bison
6 Copyright (C) 2003 Frank Mori Hess <fmhess@users.sourceforge.net>
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation, version 2.1
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 #include "libinternal.h"
32 #define YYERROR_VERBOSE
33 #define YYPARSE_PARAM parse_arg
34 #define YYLEX_PARAM priv(YYPARSE_PARAM)->yyscanner
36 #include "calib_yacc.h"
37 #include "calib_lex.h"
39 enum polynomial_direction
48 comedi_calibration_t *parsed_file;
49 comedi_caldac_t caldac;
51 unsigned num_coefficients;
52 comedi_polynomial_t polynomial;
53 } calib_yyparse_private_t;
57 static inline calib_yyparse_private_t* priv( calib_yyparse_private_t *parse_arg)
62 static void free_calibration_setting( comedi_calibration_setting_t *setting )
64 if( setting->channels );
66 free( setting->channels );
67 setting->channels = NULL;
68 setting->num_channels = 0;
70 if( setting->ranges );
72 free( setting->ranges );
73 setting->ranges = NULL;
74 setting->num_ranges = 0;
76 setting->num_arefs = 0;
77 if( setting->caldacs );
79 free( setting->caldacs );
80 setting->caldacs = NULL;
81 setting->num_caldacs = 0;
83 if(setting->soft_calibration.to_phys)
85 free(setting->soft_calibration.to_phys);
86 setting->soft_calibration.to_phys = NULL;
88 if(setting->soft_calibration.from_phys)
90 free(setting->soft_calibration.from_phys);
91 setting->soft_calibration.from_phys = NULL;
95 static void free_settings( comedi_calibration_t *file_contents )
99 if( file_contents->settings == NULL ) return;
101 for( i = 0; i < file_contents->num_settings; i++ )
103 free_calibration_setting( &file_contents->settings[ i ] );
105 free(file_contents->settings);
106 file_contents->settings = NULL;
109 static int add_calibration_setting( comedi_calibration_t *file_contents )
111 comedi_calibration_setting_t *temp;
113 temp = realloc( file_contents->settings,
114 ( file_contents->num_settings + 1 ) * sizeof( comedi_calibration_setting_t ) );
117 fprintf(stderr, "%s: realloc failed to allocate memory.\n", __FUNCTION__);
120 file_contents->settings = temp;
121 memset( &file_contents->settings[ file_contents->num_settings ],
122 0, sizeof( comedi_calibration_setting_t ) );
124 file_contents->num_settings++;
128 static comedi_calibration_setting_t* current_setting( calib_yyparse_private_t *priv )
132 while( priv->cal_index >= priv->parsed_file->num_settings )
134 retval = add_calibration_setting( priv->parsed_file );
135 if( retval < 0 ) return NULL;
137 return &priv->parsed_file->settings[ priv->cal_index ];
140 static int add_channel( calib_yyparse_private_t *priv, int channel )
143 comedi_calibration_setting_t *setting;
145 setting = current_setting( priv );
146 if( setting == NULL ) return -1;
148 temp = realloc( setting->channels, ( setting->num_channels + 1 ) * sizeof(unsigned) );
151 fprintf(stderr, "%s: realloc failed to allocate memory.\n", __FUNCTION__);
154 setting->channels = temp;
155 setting->channels[ setting->num_channels++ ] = channel;
159 static int add_range( calib_yyparse_private_t *priv, int range )
162 comedi_calibration_setting_t *setting;
164 setting = current_setting( priv );
165 if( setting == NULL ) return -1;
167 temp = realloc( setting->ranges, ( setting->num_ranges + 1 ) * sizeof(unsigned) );
170 fprintf(stderr, "%s: realloc failed to allocate memory.\n", __FUNCTION__);
173 setting->ranges = temp;
174 setting->ranges[ setting->num_ranges++ ] = range;
178 static int add_aref( calib_yyparse_private_t *priv, int aref )
180 comedi_calibration_setting_t *setting;
182 setting = current_setting( priv );
183 if( setting == NULL ) return -1;
185 if( setting->num_arefs >= sizeof( setting->arefs ) /
186 sizeof( setting->arefs[ 0 ] ) )
188 setting->arefs[ setting->num_arefs++ ] = aref;
192 static int add_caldac( calib_yyparse_private_t *priv,
193 comedi_caldac_t caldac )
195 comedi_caldac_t *temp;
196 comedi_calibration_setting_t *setting;
198 setting = current_setting( priv );
199 if( setting == NULL ) return -1;
201 temp = realloc( setting->caldacs, ( setting->num_caldacs + 1 ) *
202 sizeof( comedi_caldac_t ) );
205 fprintf(stderr, "%s: realloc failed to allocate memory.\n", __FUNCTION__);
208 setting->caldacs = temp;
209 setting->caldacs[ setting->num_caldacs++ ] = caldac;
213 static int add_polynomial(calib_yyparse_private_t *priv, enum polynomial_direction polynomial_direction)
215 comedi_calibration_setting_t *setting;
217 setting = current_setting( priv );
218 if( setting == NULL )
220 fprintf(stderr, "%s: current_setting returned NULL\n", __FUNCTION__);
223 if(priv->num_coefficients < 1)
225 fprintf(stderr, "%s: polynomial has no coefficients.\n", __FUNCTION__);
228 if(polynomial_direction == POLYNOMIAL_TO_PHYS)
230 if(setting->soft_calibration.to_phys) return -1;
231 setting->soft_calibration.to_phys = malloc(sizeof(comedi_polynomial_t));
232 *setting->soft_calibration.to_phys = priv->polynomial;
235 if(setting->soft_calibration.from_phys) return -1;
236 setting->soft_calibration.from_phys = malloc(sizeof(comedi_polynomial_t));
237 *setting->soft_calibration.from_phys = priv->polynomial;
242 static int add_polynomial_coefficient(calib_yyparse_private_t *priv, double coefficient)
244 if(priv->num_coefficients >= COMEDI_MAX_NUM_POLYNOMIAL_COEFFICIENTS)
246 fprintf(stderr, "too many coefficients for polynomial,\n");
247 fprintf(stderr, "num_coefficients=%i, max is %i .\n", priv->num_coefficients, COMEDI_MAX_NUM_POLYNOMIAL_COEFFICIENTS);
250 priv->polynomial.order = priv->num_coefficients;
251 priv->polynomial.coefficients[priv->num_coefficients++] = coefficient;
255 static comedi_calibration_t* alloc_calib_parse( void )
257 comedi_calibration_t *file_contents;
259 file_contents = malloc( sizeof( *file_contents ) );
260 if( file_contents == NULL ) return file_contents;
261 memset( file_contents, 0, sizeof( *file_contents ) );
262 return file_contents;
265 EXPORT_ALIAS_DEFAULT(_comedi_cleanup_calibration,comedi_cleanup_calibration,0.7.20);
266 extern void _comedi_cleanup_calibration( comedi_calibration_t *file_contents )
268 if(file_contents == NULL) return;
269 if( file_contents->driver_name )
271 free( file_contents->driver_name );
272 file_contents->driver_name = NULL;
274 if( file_contents->board_name )
276 free( file_contents->board_name );
277 file_contents->board_name = NULL;
279 free_settings( file_contents );
280 free( file_contents );
283 static comedi_polynomial_t* alloc_inverse_linear_polynomial(const comedi_polynomial_t *polynomial)
285 comedi_polynomial_t *inverse;
286 if(polynomial->order != 1) return NULL;
287 inverse = malloc(sizeof(comedi_polynomial_t));
288 memset(inverse, 0, sizeof(comedi_polynomial_t));
290 inverse->expansion_origin = polynomial->coefficients[0];
291 inverse->coefficients[0] = polynomial->expansion_origin;
292 inverse->coefficients[1] = 1. / polynomial->coefficients[1];
293 if(isfinite(inverse->coefficients[1]) == 0)
301 static void fill_inverse_linear_polynomials(comedi_calibration_t *calibration)
304 for(i = 0; i < calibration->num_settings; ++i)
306 if(calibration->settings[i].soft_calibration.to_phys)
308 if(calibration->settings[i].soft_calibration.from_phys == NULL)
310 calibration->settings[i].soft_calibration.from_phys =
311 alloc_inverse_linear_polynomial(calibration->settings[i].soft_calibration.to_phys);
313 }else if(calibration->settings[i].soft_calibration.from_phys)
315 calibration->settings[i].soft_calibration.to_phys =
316 alloc_inverse_linear_polynomial(calibration->settings[i].soft_calibration.from_phys);
321 static void yyerror(const char *s)
323 fprintf(stderr, "%s\n", s);
337 %token T_DRIVER_NAME T_BOARD_NAME T_CALIBRATIONS T_SUBDEVICE T_CHANNELS
338 %token T_RANGES T_AREFS T_CALDACS T_CHANNEL T_VALUE T_NUMBER T_STRING
339 %token T_COEFFICIENTS T_EXPANSION_ORIGIN T_SOFTCAL_TO_PHYS T_SOFTCAL_FROM_PHYS
340 %token T_ASSIGN T_FLOAT
342 %type <ival> T_NUMBER
343 %type <sval> T_STRING
351 fprintf(stderr, "input error on line %i\n", calib_yyget_lineno(priv(parse_arg)->yyscanner));
352 // fprintf(stderr, "input error on line %i\n", @1.first_line );
359 | hash_element ',' hash
362 hash_element: T_DRIVER_NAME T_ASSIGN T_STRING
364 if( priv(parse_arg)->parsed_file->driver_name != NULL ) YYABORT;
365 priv(parse_arg)->parsed_file->driver_name = strdup( $3 );
367 | T_BOARD_NAME T_ASSIGN T_STRING
369 if( priv(parse_arg)->parsed_file->board_name != NULL ) YYABORT;
370 priv(parse_arg)->parsed_file->board_name = strdup( $3 );
372 | T_CALIBRATIONS T_ASSIGN '[' calibrations_array ']'
375 calibrations_array: /* empty */
376 | '{' calibration_setting '}'
377 | '{' calibration_setting '}' ',' calibrations_array
380 calibration_setting: /* empty */ { priv(parse_arg)->cal_index++; }
381 | calibration_setting_element { priv(parse_arg)->cal_index++; }
382 | calibration_setting_element ',' calibration_setting
385 calibration_setting_element: T_SUBDEVICE T_ASSIGN T_NUMBER
387 comedi_calibration_setting_t *setting;
388 setting = current_setting( parse_arg );
389 if( setting == NULL ) YYABORT;
390 setting->subdevice = $3;
392 | T_CHANNELS T_ASSIGN '[' channels_array ']'
393 | T_RANGES T_ASSIGN '[' ranges_array ']'
394 | T_AREFS T_ASSIGN '[' arefs_array ']'
395 | T_CALDACS T_ASSIGN '[' caldacs_array ']'
396 | T_SOFTCAL_TO_PHYS T_ASSIGN '{' polynomial '}'
398 if(add_polynomial(parse_arg, POLYNOMIAL_TO_PHYS) < 0) YYERROR;
399 priv(parse_arg)->num_coefficients = 0;
401 | T_SOFTCAL_FROM_PHYS T_ASSIGN '{' polynomial '}'
403 if(add_polynomial(parse_arg, POLYNOMIAL_FROM_PHYS) < 0) YYERROR;
404 priv(parse_arg)->num_coefficients = 0;
408 channels_array: /* empty */
410 | channel ',' channels_array
413 channel: T_NUMBER { if(add_channel( parse_arg, $1 ) < 0) YYERROR; }
416 ranges_array: /* empty */
418 | range ',' ranges_array
421 range: T_NUMBER { if(add_range( parse_arg, $1 ) < 0) YYERROR; }
424 arefs_array: /* empty */
426 | aref ',' arefs_array
429 aref: T_NUMBER { if(add_aref( parse_arg, $1 ) < 0) YYERROR; }
432 caldacs_array: /* empty */
434 | '{' caldac '}' ',' caldacs_array
437 caldac: /* empty */ { if(add_caldac( parse_arg, priv(parse_arg)->caldac ) < 0) YYERROR; }
438 | caldac_element { if(add_caldac( parse_arg, priv(parse_arg)->caldac ) < 0) YYERROR; }
439 | caldac_element ',' caldac
442 caldac_element: T_SUBDEVICE T_ASSIGN T_NUMBER { priv(parse_arg)->caldac.subdevice = $3; }
443 | T_CHANNEL T_ASSIGN T_NUMBER { priv(parse_arg)->caldac.channel = $3; }
444 | T_VALUE T_ASSIGN T_NUMBER { priv(parse_arg)->caldac.value = $3; }
447 polynomial: /* empty */
449 | polynomial_element ',' polynomial
452 polynomial_element: T_COEFFICIENTS T_ASSIGN '[' coefficient_array ']'
453 | T_EXPANSION_ORIGIN T_ASSIGN expansion_origin
456 coefficient_array: /* empty */
458 | coefficient ',' coefficient_array
463 if(add_polynomial_coefficient(parse_arg, $1) < 0) YYERROR;
467 if(add_polynomial_coefficient(parse_arg, $1) < 0) YYERROR;
471 expansion_origin: T_FLOAT
473 priv(parse_arg)->polynomial.expansion_origin = $1;
477 priv(parse_arg)->polynomial.expansion_origin = $1;
484 EXPORT_ALIAS_DEFAULT(_comedi_parse_calibration_file,comedi_parse_calibration_file,0.7.20);
485 extern comedi_calibration_t* _comedi_parse_calibration_file( const char *cal_file_path )
487 calib_yyparse_private_t priv;
490 if( cal_file_path == NULL ) return NULL;
491 memset(&priv, 0, sizeof(calib_yyparse_private_t));
492 priv.parsed_file = alloc_calib_parse();
493 if( priv.parsed_file == NULL ) return NULL;
495 file = fopen( cal_file_path, "r" );
498 COMEDILIB_DEBUG( 3, "failed to open file\n" );
501 calib_yylex_init(&priv.yyscanner);
502 calib_yyrestart(file, priv.yyscanner);
503 if( calib_yyparse( &priv ) )
505 comedi_cleanup_calibration( priv.parsed_file );
506 priv.parsed_file = NULL;
508 calib_yylex_destroy(priv.yyscanner);
510 fill_inverse_linear_polynomials(priv.parsed_file);
511 return priv.parsed_file;