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"
31 #include "calib_yacc.h"
32 #include "calib_lex.h"
34 #define YYERROR_VERBOSE
35 #define YYPARSE_PARAM parse_arg
36 #define YYLEX_PARAM priv(YYPARSE_PARAM)->yyscanner
38 enum polynomial_direction
47 comedi_calibration_t *parsed_file;
48 comedi_caldac_t caldac;
50 unsigned num_coefficients;
51 comedi_polynomial_t polynomial;
52 } calib_yyparse_private_t;
56 static inline calib_yyparse_private_t* priv( calib_yyparse_private_t *parse_arg)
61 static void free_calibration_setting( comedi_calibration_setting_t *setting )
63 if( setting->channels );
65 free( setting->channels );
66 setting->channels = NULL;
67 setting->num_channels = 0;
69 if( setting->ranges );
71 free( setting->ranges );
72 setting->ranges = NULL;
73 setting->num_ranges = 0;
75 setting->num_arefs = 0;
76 if( setting->caldacs );
78 free( setting->caldacs );
79 setting->caldacs = NULL;
80 setting->num_caldacs = 0;
82 if(setting->soft_calibration.to_phys)
84 free(setting->soft_calibration.to_phys);
85 setting->soft_calibration.to_phys = NULL;
87 if(setting->soft_calibration.from_phys)
89 free(setting->soft_calibration.from_phys);
90 setting->soft_calibration.from_phys = NULL;
94 static void free_settings( comedi_calibration_t *file_contents )
98 if( file_contents->settings == NULL ) return;
100 for( i = 0; i < file_contents->num_settings; i++ )
102 free_calibration_setting( &file_contents->settings[ i ] );
104 file_contents->settings = NULL;
107 static int add_calibration_setting( comedi_calibration_t *file_contents )
109 comedi_calibration_setting_t *temp;
111 temp = realloc( file_contents->settings,
112 ( file_contents->num_settings + 1 ) * sizeof( comedi_calibration_setting_t ) );
115 fprintf(stderr, "%s: realloc failed to allocate memory.\n", __FUNCTION__);
118 file_contents->settings = temp;
119 memset( &file_contents->settings[ file_contents->num_settings ],
120 0, sizeof( comedi_calibration_setting_t ) );
122 file_contents->num_settings++;
126 static comedi_calibration_setting_t* current_setting( calib_yyparse_private_t *priv )
130 while( priv->cal_index >= priv->parsed_file->num_settings )
132 retval = add_calibration_setting( priv->parsed_file );
133 if( retval < 0 ) return NULL;
135 return &priv->parsed_file->settings[ priv->cal_index ];
138 static int add_channel( calib_yyparse_private_t *priv, int channel )
141 comedi_calibration_setting_t *setting;
143 setting = current_setting( priv );
144 if( setting == NULL ) return -1;
146 temp = realloc( setting->channels, ( setting->num_channels + 1 ) * sizeof(unsigned) );
149 fprintf(stderr, "%s: realloc failed to allocate memory.\n", __FUNCTION__);
152 setting->channels = temp;
153 setting->channels[ setting->num_channels++ ] = channel;
157 static int add_range( calib_yyparse_private_t *priv, int range )
160 comedi_calibration_setting_t *setting;
162 setting = current_setting( priv );
163 if( setting == NULL ) return -1;
165 temp = realloc( setting->ranges, ( setting->num_ranges + 1 ) * sizeof(unsigned) );
168 fprintf(stderr, "%s: realloc failed to allocate memory.\n", __FUNCTION__);
171 setting->ranges = temp;
172 setting->ranges[ setting->num_ranges++ ] = range;
176 static int add_aref( calib_yyparse_private_t *priv, int aref )
178 comedi_calibration_setting_t *setting;
180 setting = current_setting( priv );
181 if( setting == NULL ) return -1;
183 if( setting->num_arefs >= sizeof( setting->arefs ) /
184 sizeof( setting->arefs[ 0 ] ) )
186 setting->arefs[ setting->num_arefs++ ] = aref;
190 static int add_caldac( calib_yyparse_private_t *priv,
191 comedi_caldac_t caldac )
193 comedi_caldac_t *temp;
194 comedi_calibration_setting_t *setting;
196 setting = current_setting( priv );
197 if( setting == NULL ) return -1;
199 temp = realloc( setting->caldacs, ( setting->num_caldacs + 1 ) *
200 sizeof( comedi_caldac_t ) );
203 fprintf(stderr, "%s: realloc failed to allocate memory.\n", __FUNCTION__);
206 setting->caldacs = temp;
207 setting->caldacs[ setting->num_caldacs++ ] = caldac;
211 static int add_polynomial(calib_yyparse_private_t *priv, enum polynomial_direction polynomial_direction)
213 comedi_calibration_setting_t *setting;
215 setting = current_setting( priv );
216 if( setting == NULL )
218 fprintf(stderr, "%s: current_setting returned NULL\n", __FUNCTION__);
221 if(priv->num_coefficients < 1)
223 fprintf(stderr, "%s: polynomial has no coefficients.\n", __FUNCTION__);
226 if(polynomial_direction == POLYNOMIAL_TO_PHYS)
228 if(setting->soft_calibration.to_phys) return -1;
229 setting->soft_calibration.to_phys = malloc(sizeof(comedi_polynomial_t));
230 *setting->soft_calibration.to_phys = priv->polynomial;
233 if(setting->soft_calibration.from_phys) return -1;
234 setting->soft_calibration.from_phys = malloc(sizeof(comedi_polynomial_t));
235 *setting->soft_calibration.from_phys = priv->polynomial;
240 static int add_polynomial_coefficient(calib_yyparse_private_t *priv, double coefficient)
242 if(priv->num_coefficients >= COMEDI_MAX_NUM_POLYNOMIAL_COEFFICIENTS)
244 fprintf(stderr, "too many coefficients for polynomial,\n");
245 fprintf(stderr, "num_coefficients=%i, max is %i .\n", priv->num_coefficients, COMEDI_MAX_NUM_POLYNOMIAL_COEFFICIENTS);
248 priv->polynomial.order = priv->num_coefficients;
249 priv->polynomial.coefficients[priv->num_coefficients++] = coefficient;
253 static comedi_calibration_t* alloc_calib_parse( void )
255 comedi_calibration_t *file_contents;
257 file_contents = malloc( sizeof( *file_contents ) );
258 if( file_contents == NULL ) return file_contents;
259 memset( file_contents, 0, sizeof( *file_contents ) );
260 return file_contents;
263 EXPORT_ALIAS_DEFAULT(_comedi_cleanup_calibration,comedi_cleanup_calibration,0.7.20);
264 extern void _comedi_cleanup_calibration( comedi_calibration_t *file_contents )
266 if( file_contents->driver_name )
268 free( file_contents->driver_name );
269 file_contents->driver_name = NULL;
271 if( file_contents->board_name )
273 free( file_contents->board_name );
274 file_contents->board_name = NULL;
276 free_settings( file_contents );
277 free( file_contents );
280 static comedi_polynomial_t* alloc_inverse_linear_polynomial(const comedi_polynomial_t *polynomial)
282 comedi_polynomial_t *inverse;
283 if(polynomial->order != 1) return NULL;
284 inverse = malloc(sizeof(comedi_polynomial_t));
285 memset(inverse, 0, sizeof(comedi_polynomial_t));
287 inverse->expansion_origin = polynomial->coefficients[0];
288 inverse->coefficients[0] = polynomial->expansion_origin;
289 inverse->coefficients[1] = 1. / polynomial->coefficients[1];
290 if(isfinite(inverse->coefficients[1]) == 0)
298 static void fill_inverse_linear_polynomials(comedi_calibration_t *calibration)
301 for(i = 0; i < calibration->num_settings; ++i)
303 if(calibration->settings[i].soft_calibration.to_phys)
305 if(calibration->settings[i].soft_calibration.from_phys == NULL)
307 calibration->settings[i].soft_calibration.from_phys =
308 alloc_inverse_linear_polynomial(calibration->settings[i].soft_calibration.to_phys);
310 }else if(calibration->settings[i].soft_calibration.from_phys)
312 calibration->settings[i].soft_calibration.to_phys =
313 alloc_inverse_linear_polynomial(calibration->settings[i].soft_calibration.from_phys);
318 EXPORT_ALIAS_DEFAULT(_comedi_parse_calibration_file,comedi_parse_calibration_file,0.7.20);
319 extern comedi_calibration_t* _comedi_parse_calibration_file( const char *cal_file_path )
321 calib_yyparse_private_t priv;
324 if( cal_file_path == NULL ) return NULL;
325 memset(&priv, 0, sizeof(calib_yyparse_private_t));
326 priv.parsed_file = alloc_calib_parse();
327 if( priv.parsed_file == NULL ) return NULL;
329 file = fopen( cal_file_path, "r" );
332 COMEDILIB_DEBUG( 3, "failed to open file\n" );
335 calib_yylex_init(&priv.yyscanner);
336 calib_yyrestart(file, priv.yyscanner);
337 if( calib_yyparse( &priv ) )
339 comedi_cleanup_calibration( priv.parsed_file );
340 priv.parsed_file = NULL;
342 calib_yylex_destroy(priv.yyscanner);
344 fill_inverse_linear_polynomials(priv.parsed_file);
345 return priv.parsed_file;
359 %token T_DRIVER_NAME T_BOARD_NAME T_CALIBRATIONS T_SUBDEVICE T_CHANNELS
360 %token T_RANGES T_AREFS T_CALDACS T_CHANNEL T_VALUE T_NUMBER T_STRING
361 %token T_COEFFICIENTS T_EXPANSION_ORIGIN T_SOFTCAL_TO_PHYS T_SOFTCAL_FROM_PHYS
362 %token T_ASSIGN T_FLOAT
364 %type <ival> T_NUMBER
365 %type <sval> T_STRING
373 fprintf(stderr, "input error on line %i\n", calib_yyget_lineno(priv(parse_arg)->yyscanner));
374 // fprintf(stderr, "input error on line %i\n", @1.first_line );
381 | hash_element ',' hash
384 hash_element: T_DRIVER_NAME T_ASSIGN T_STRING
386 if( priv(parse_arg)->parsed_file->driver_name != NULL ) YYABORT;
387 priv(parse_arg)->parsed_file->driver_name = strdup( $3 );
389 | T_BOARD_NAME T_ASSIGN T_STRING
391 if( priv(parse_arg)->parsed_file->board_name != NULL ) YYABORT;
392 priv(parse_arg)->parsed_file->board_name = strdup( $3 );
394 | T_CALIBRATIONS T_ASSIGN '[' calibrations_array ']'
397 calibrations_array: /* empty */
398 | '{' calibration_setting '}'
399 | '{' calibration_setting '}' ',' calibrations_array
402 calibration_setting: /* empty */ { priv(parse_arg)->cal_index++; }
403 | calibration_setting_element { priv(parse_arg)->cal_index++; }
404 | calibration_setting_element ',' calibration_setting
407 calibration_setting_element: T_SUBDEVICE T_ASSIGN T_NUMBER
409 comedi_calibration_setting_t *setting;
410 setting = current_setting( parse_arg );
411 if( setting == NULL ) YYABORT;
412 setting->subdevice = $3;
414 | T_CHANNELS T_ASSIGN '[' channels_array ']'
415 | T_RANGES T_ASSIGN '[' ranges_array ']'
416 | T_AREFS T_ASSIGN '[' arefs_array ']'
417 | T_CALDACS T_ASSIGN '[' caldacs_array ']'
418 | T_SOFTCAL_TO_PHYS T_ASSIGN '{' polynomial '}'
420 if(add_polynomial(parse_arg, POLYNOMIAL_TO_PHYS) < 0) YYERROR;
421 priv(parse_arg)->num_coefficients = 0;
423 | T_SOFTCAL_FROM_PHYS T_ASSIGN '{' polynomial '}'
425 if(add_polynomial(parse_arg, POLYNOMIAL_FROM_PHYS) < 0) YYERROR;
426 priv(parse_arg)->num_coefficients = 0;
430 channels_array: /* empty */
432 | channel ',' channels_array
435 channel: T_NUMBER { if(add_channel( parse_arg, $1 ) < 0) YYERROR; }
438 ranges_array: /* empty */
440 | range ',' ranges_array
443 range: T_NUMBER { if(add_range( parse_arg, $1 ) < 0) YYERROR; }
446 arefs_array: /* empty */
448 | aref ',' arefs_array
451 aref: T_NUMBER { if(add_aref( parse_arg, $1 ) < 0) YYERROR; }
454 caldacs_array: /* empty */
456 | '{' caldac '}' ',' caldacs_array
459 caldac: /* empty */ { if(add_caldac( parse_arg, priv(parse_arg)->caldac ) < 0) YYERROR; }
460 | caldac_element { if(add_caldac( parse_arg, priv(parse_arg)->caldac ) < 0) YYERROR; }
461 | caldac_element ',' caldac
464 caldac_element: T_SUBDEVICE T_ASSIGN T_NUMBER { priv(parse_arg)->caldac.subdevice = $3; }
465 | T_CHANNEL T_ASSIGN T_NUMBER { priv(parse_arg)->caldac.channel = $3; }
466 | T_VALUE T_ASSIGN T_NUMBER { priv(parse_arg)->caldac.value = $3; }
469 polynomial: /* empty */
471 | polynomial_element ',' polynomial
474 polynomial_element: T_COEFFICIENTS T_ASSIGN '[' coefficient_array ']'
475 | T_EXPANSION_ORIGIN T_ASSIGN expansion_origin
478 coefficient_array: /* empty */
480 | coefficient ',' coefficient_array
485 if(add_polynomial_coefficient(parse_arg, $1) < 0) YYERROR;
489 if(add_polynomial_coefficient(parse_arg, $1) < 0) YYERROR;
493 expansion_origin: T_FLOAT
495 priv(parse_arg)->polynomial.expansion_origin = $1;
499 priv(parse_arg)->polynomial.expansion_origin = $1;
505 void calib_yyerror(char *s)
507 fprintf(stderr, "%s\n", s);