grammar blinkenlight_panel_config; options { language=C; } // parser actions fill "blinkenlight_panels" structs of // the config database tree @header { #include #include "config.h" // global panel config extern blinkenlight_panel_list_t *blinkenlight_panel_list ; } /**/ /*------------------------------------------------------------------ * LEXER RULES *------------------------------------------------------------------*/ // some reserved words. UPPERCASE, since case insensitive lexing is enabled // in the program PANEL : 'PANEL' ; CONTROL : 'CONTROL' ; NAME : 'NAME' ; RADIX : 'RADIX' ; TYPE : 'TYPE' ; TYPE_SWITCH : 'SWITCH' {USER1=1;} ; // USER1 = blinkenlight_control_type_enum code! TYPE_LAMP : 'LAMP' {USER1=2;} ; ENCODING: 'ENCODING' ; ENCODING_BINARY : 'BINARY' {USER1=1;} ; // USER1 = blinkenlight_control_value_encoding_enum code! ENCODING_BITPOSITION : 'BITPOSITION' {USER1=2;}; DEFAULT : 'DEFAULT'; BLINKENBUS_WIRING : 'BLINKENBUS_WIRING' ; REGISTER_WIRING : 'REGISTER_WIRING' ; VALUE_BIT_OFFSET : 'VALUE_BIT_OFFSET' ; LEVELS : 'LEVELS' ; ACTIVE_HIGH : 'ACTIVE_HIGH' {USER1=0;} ; // USER1: value for blinkenbus_levels_active_low ACTIVE_LOW : 'ACTIVE_LOW' {USER1=1;}; BOARD : 'BOARD' ; REGISTER : 'REGISTER' ; // register names are fixed tokens. // User1 = register space (0=output, 1 = input) // User2= register address on board // needs another implementation, if more board types are build IN0 : 'IN0' {USER1=1;USER2=0;} ; IN1 : 'IN1' {USER1=1;USER2=1;} ; IN2 : 'IN2' {USER1=1;USER2=2;} ; IN3 : 'IN3' {USER1=1;USER2=3;} ; IN4 : 'IN4' {USER1=1;USER2=4;} ; OUT0 : 'OUT0' {USER1=0;USER2=0;} ; OUT1 : 'OUT1' {USER1=0;USER2=1;} ; OUT2 : 'OUT2' {USER1=0;USER2=2;} ; OUT3 : 'OUT3' {USER1=0;USER2=3;} ; OUT4 : 'OUT4' {USER1=0;USER2=4;} ; OUT5 : 'OUT5' {USER1=0;USER2=5;} ; OUT6 : 'OUT6' {USER1=0;USER2=6;} ; OUT7 : 'OUT7' {USER1=0;USER2=7;} ; OUT8 : 'OUT8' {USER1=0;USER2=8;} ; OUT9 : 'OUT9' {USER1=0;USER2=9;} ; OUT10 : 'OUT10' {USER1=0;USER2=10;} ; BITS : 'BITS' ; DIGITS: '1'..'9' '0'..'9'*; OCTAL_DIGITS: '0' '0'..'7'+; HEX_DIGITS: '0X' ('0'..'9' | 'a'..'f' | 'A'..'F')+; ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ; COMMENT : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;} | '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;} ; WS : ( ' ' | '\t' | '\r' | '\n' ) {$channel=HIDDEN;} ; STRING : '"' ( ESC_SEQ | ~('\\'|'"') )* '"' ; CHAR: '\'' ( ESC_SEQ | ~('\''|'\\') ) '\'' ; fragment HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ; fragment ESC_SEQ : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') | UNICODE_ESC | OCTAL_ESC ; fragment OCTAL_ESC : '\\' ('0'..'3') ('0'..'7') ('0'..'7') | '\\' ('0'..'7') ('0'..'7') | '\\' ('0'..'7') ; fragment UNICODE_ESC : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT ; /*------------------------------------------------------------------ * PARSER RULES *------------------------------------------------------------------*/ panel_list : panel_definition (';' panel_definition)* (';')? ; panel_definition : PANEL '=' { parser_cur_panel = blinkenlight_add_panel(blinkenlight_panel_list) ;} '{' panel_parameter (',' panel_parameter)* '}' ; panel_parameter : NAME '=' panel_name = STRING { char *s = parser_strip_quotes($panel_name.text->chars) ; strncpy(parser_cur_panel->name, s, sizeof(parser_cur_panel->name));} | RADIX '=' radix = unsigned_int {parser_cur_panel->default_radix = $radix.value;} | control_definition ; control_definition : CONTROL '=' { parser_cur_control = blinkenlight_add_control(blinkenlight_panel_list, parser_cur_panel) ;} '{' control_parameter (',' control_parameter)* '}' ; control_parameter : NAME '=' control_name = STRING { strcpy(parser_cur_control->name, parser_strip_quotes($control_name.text->chars));} // { printf("NAME=\%s\n", $control_name.text->chars) ;} | TYPE '=' control_type = (TYPE_SWITCH | TYPE_LAMP) { parser_cur_control->type = $control_type->user1 ; } // { printf("TYPE=\%d\n", $control_type->user1) ;} | ENCODING '=' control_encoding = (ENCODING_BINARY | ENCODING_BITPOSITION) { parser_cur_control->encoding = $control_encoding->user1 ; } | DEFAULT '=' default_value=unsigned_int{parser_cur_control->value_default = $default_value.value;} // { printf("ENCODING=\%d\n", $control_encoding->user1) ;} | RADIX '=' radix = unsigned_int {parser_cur_control->radix = $radix.value;} | BLINKENBUS_WIRING '=' register_wiring_list ; register_wiring_list : '{' register_wiring (',' register_wiring)* '}' ; register_wiring : REGISTER_WIRING '=' { parser_cur_register_wiring = parser_add_register_wiring(parser_cur_control) ;} '{' register_wiring_parameter (',' register_wiring_parameter)* '}' ; register_wiring_parameter : VALUE_BIT_OFFSET '=' unsigned_int {parser_cur_register_wiring->control_value_bit_offset = $unsigned_int.value;} | BOARD '=' unsigned_int {parser_cur_register_wiring->blinkenbus_board_address = $unsigned_int.value;} | REGISTER '=' in_out=(IN0|IN1|IN2|IN3|IN4 | OUT0|OUT1|OUT2|OUT3|OUT4| OUT5|OUT6|OUT7|OUT8|OUT9|OUT10) {parser_cur_register_wiring->board_register_space = in_out->user1; parser_cur_register_wiring->board_register_address = in_out->user2;} | BITS '=' lsb = unsigned_int {parser_cur_register_wiring->blinkenbus_lsb = parser_cur_register_wiring->blinkenbus_msb = $lsb.value;} ('..' msb=unsigned_int {parser_cur_register_wiring->blinkenbus_msb = $msb.value;} )? | LEVELS '=' polarity=(ACTIVE_HIGH | ACTIVE_LOW) {parser_cur_register_wiring->blinkenbus_levels_active_low = polarity->user1; } ; unsigned_int returns [long value] : '0'{$value = 0;} | DIGITS {$value = strtol($DIGITS.text->chars,NULL,10) ;} | OCTAL_DIGITS {$value = strtol(($OCTAL_DIGITS.text->chars)+1,NULL,8) ;} // "+1": strip prefix "0" | HEX_DIGITS {$value = strtol(($HEX_DIGITS.text->chars)+2,NULL,16) ;} // "+2": strip prefix "0x" ;