%{ /* lib/calib_yacc.y code for parsing calibration file, generated by bison Copyright (C) 2003 Frank Mori Hess This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include "libinternal.h" #include #include #include "calib_yacc.h" #define YYERROR_VERBOSE #define YYPARSE_PARAM parse_arg typedef struct { comedi_calibration_t *parsed_file; comedi_caldac_t caldac; int cal_index; } calib_yyparse_private_t; YY_DECL; static inline calib_yyparse_private_t* priv( calib_yyparse_private_t *parse_arg) { return parse_arg; } static void free_calibration_setting( comedi_calibration_setting_t *setting ) { if( setting->channels ); { free( setting->channels ); setting->channels = NULL; setting->num_channels = 0; } if( setting->ranges ); { free( setting->ranges ); setting->ranges = NULL; setting->num_ranges = 0; } setting->num_arefs = 0; if( setting->caldacs ); { free( setting->caldacs ); setting->caldacs = NULL; setting->num_caldacs = 0; } } static void free_settings( comedi_calibration_t *file_contents ) { int i; if( file_contents->settings == NULL ) return; for( i = 0; i < file_contents->num_settings; i++ ) { free_calibration_setting( &file_contents->settings[ i ] ); } file_contents->settings = NULL; } static int add_calibration_setting( comedi_calibration_t *file_contents ) { comedi_calibration_setting_t *temp; temp = realloc( file_contents->settings, ( file_contents->num_settings + 1 ) * sizeof( comedi_calibration_setting_t ) ); if( temp == NULL ) return -1; file_contents->settings = temp; memset( &file_contents->settings[ file_contents->num_settings ], 0, sizeof( comedi_calibration_setting_t ) ); file_contents->num_settings++; return 0; } static comedi_calibration_setting_t* current_setting( calib_yyparse_private_t *priv ) { int retval; while( priv->cal_index >= priv->parsed_file->num_settings ) { retval = add_calibration_setting( priv->parsed_file ); if( retval < 0 ) return NULL; } return &priv->parsed_file->settings[ priv->cal_index ]; } static int add_channel( calib_yyparse_private_t *priv, int channel ) { int *temp; comedi_calibration_setting_t *setting; setting = current_setting( priv ); if( setting == NULL ) return -1; temp = realloc( setting->channels, ( setting->num_channels + 1 ) * sizeof( int ) ); if( temp == NULL ) return -1; setting->channels = temp; setting->channels[ setting->num_channels++ ] = channel; return 0; } static int add_range( calib_yyparse_private_t *priv, int range ) { int *temp; comedi_calibration_setting_t *setting; setting = current_setting( priv ); if( setting == NULL ) return -1; temp = realloc( setting->ranges, ( setting->num_ranges + 1 ) * sizeof( int ) ); if( temp == NULL ) return -1; setting->ranges = temp; setting->ranges[ setting->num_ranges++ ] = range; return 0; } static int add_aref( calib_yyparse_private_t *priv, int aref ) { comedi_calibration_setting_t *setting; setting = current_setting( priv ); if( setting == NULL ) return -1; if( setting->num_arefs >= sizeof( setting->arefs ) / sizeof( setting->arefs[ 0 ] ) ) return -1; setting->arefs[ setting->num_arefs++ ] = aref; return 0; } static int add_caldac( calib_yyparse_private_t *priv, comedi_caldac_t caldac ) { comedi_caldac_t *temp; comedi_calibration_setting_t *setting; setting = current_setting( priv ); if( setting == NULL ) return -1; temp = realloc( setting->caldacs, ( setting->num_caldacs + 1 ) * sizeof( comedi_caldac_t ) ); if( temp == NULL ) return -1; setting->caldacs = temp; setting->caldacs[ setting->num_caldacs++ ] = caldac; return 0; } static comedi_calibration_t* alloc_calib_parse( void ) { comedi_calibration_t *file_contents; file_contents = malloc( sizeof( *file_contents ) ); if( file_contents == NULL ) return file_contents; memset( file_contents, 0, sizeof( *file_contents ) ); return file_contents; } EXPORT_ALIAS_DEFAULT(_comedi_cleanup_calibration,comedi_cleanup_calibration,0.7.20); extern void _comedi_cleanup_calibration( comedi_calibration_t *file_contents ) { if( file_contents->driver_name ) { free( file_contents->driver_name ); file_contents->driver_name = NULL; } if( file_contents->board_name ) { free( file_contents->board_name ); file_contents->board_name = NULL; } free_settings( file_contents ); free( file_contents ); file_contents = NULL; } EXPORT_ALIAS_DEFAULT(_comedi_parse_calibration_file,comedi_parse_calibration_file,0.7.20); extern comedi_calibration_t* _comedi_parse_calibration_file( const char *cal_file_path ) { calib_yyparse_private_t priv; FILE *file; if( cal_file_path == NULL ) return NULL; priv.parsed_file = alloc_calib_parse(); if( priv.parsed_file == NULL ) return NULL; priv.cal_index = 0; file = fopen( cal_file_path, "r" ); if( file == NULL ) { COMEDILIB_DEBUG( 3, "failed to open file\n" ); return NULL; } calib_yyrestart( file ); if( calib_yyparse( &priv ) ) { comedi_cleanup_calibration( priv.parsed_file ); priv.parsed_file = NULL; } fclose( file ); return priv.parsed_file; } %} %pure_parser %union { int ival; char *sval; } %token T_DRIVER_NAME T_BOARD_NAME T_CALIBRATIONS T_SUBDEVICE T_CHANNELS %token T_RANGES T_AREFS T_CALDACS T_CHANNEL T_VALUE T_NUMBER T_STRING %token T_ASSIGN %type T_NUMBER %type T_STRING %% input: '{' hash '}' | error { fprintf(stderr, "input error on line %i\n", @1.first_line ); YYABORT; } ; hash: /* empty */ | hash_element | hash_element ',' hash ; hash_element: T_DRIVER_NAME T_ASSIGN T_STRING { if( priv(parse_arg)->parsed_file->driver_name != NULL ) YYABORT; priv(parse_arg)->parsed_file->driver_name = strdup( $3 ); } | T_BOARD_NAME T_ASSIGN T_STRING { if( priv(parse_arg)->parsed_file->board_name != NULL ) YYABORT; priv(parse_arg)->parsed_file->board_name = strdup( $3 ); } | T_CALIBRATIONS T_ASSIGN '[' calibrations_array ']' ; calibrations_array: /* empty */ | '{' calibration_setting '}' | '{' calibration_setting '}' ',' calibrations_array ; calibration_setting: /* empty */ { priv(parse_arg)->cal_index++; } | calibration_setting_element { priv(parse_arg)->cal_index++; } | calibration_setting_element ',' calibration_setting ; calibration_setting_element: T_SUBDEVICE T_ASSIGN T_NUMBER { comedi_calibration_setting_t *setting; setting = current_setting( parse_arg ); if( setting == NULL ) YYABORT; setting->subdevice = $3; } | T_CHANNELS T_ASSIGN '[' channels_array ']' | T_RANGES T_ASSIGN '[' ranges_array ']' | T_AREFS T_ASSIGN '[' arefs_array ']' | T_CALDACS T_ASSIGN '[' caldacs_array ']' ; channels_array: /* empty */ | channel | channel ',' channels_array ; channel: T_NUMBER { add_channel( parse_arg, $1 ); } ; ranges_array: /* empty */ | range | range ',' ranges_array ; range: T_NUMBER { add_range( parse_arg, $1 ); } ; arefs_array: /* empty */ | aref | aref ',' arefs_array ; aref: T_NUMBER { add_aref( parse_arg, $1 ); } ; caldacs_array: /* empty */ | '{' caldac '}' | '{' caldac '}' ',' caldacs_array ; caldac: /* empty */ { add_caldac( parse_arg, priv(parse_arg)->caldac ); } | caldac_element { add_caldac( parse_arg, priv(parse_arg)->caldac ); } | caldac_element ',' caldac ; caldac_element: T_SUBDEVICE T_ASSIGN T_NUMBER { priv(parse_arg)->caldac.subdevice = $3; } | T_CHANNEL T_ASSIGN T_NUMBER { priv(parse_arg)->caldac.channel = $3; } | T_VALUE T_ASSIGN T_NUMBER { priv(parse_arg)->caldac.value = $3; } ; %% void calib_yyerror(char *s) { fprintf(stderr, "%s\n", s); }