Index: hyp/parse.yy =================================================================== --- hyp/parse.yy (nonexistent) +++ hyp/parse.yy (revision 4710) @@ -0,0 +1,826 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +%code requires { +#include "hypfile.h" +} + +%parse-param {class HypFile::Hyp *hyp } +%error-verbose +%debug +%defines + +%union { + int boolval; + int intval; + double floatval; + char* strval; +} + +%{ +#include +#include +#include +#include +#include +#include +#include "parser.h" + +void yyerror(HypFile::Hyp *, const char *); + +/* YYPRINT and yyprint print values of the tokens when debugging is switched on */ +void yyprint(FILE *, int, YYSTYPE); +#define YYPRINT(file, type, value) yyprint (file, type, value) + +/* clear parse_param struct at beginning of new record */ +void new_record(); + +/* struct to pass to calling class */ +parse_param h; + +%} + +/* + * Hyperlynx keywords + */ + + /* Punctuation: { } ( ) = , */ + + /* Sections */ + +%token BOARD_FILE VERSION DATA_MODE UNITS PLANE_SEP +%token BOARD STACKUP DEVICES SUPPLIES +%token PAD PADSTACK NET NET_CLASS END KEY + + /* Keywords */ + +%token A ARC COPPER CURVE DETAILED DIELECTRIC ENGLISH LENGTH +%token LINE METRIC N OPTIONS PERIMETER_ARC PERIMETER_SEGMENT PIN +%token PLANE POLYGON POLYLINE POLYVOID POUR S SEG SIGNAL +%token SIMPLIFIED SIM_BOTH SIM_IN SIM_OUT USEG VIA WEIGHT + + /* Assignments */ + +%token A1 A2 BR C C_QM CO_QM D ER F ID +%token L L1 L2 LPS LT M NAME +%token P PKG PR_QM PS R REF SX SY S1 S1X S1Y S2 S2X S2Y T TC +%token USE_DIE_FOR_METAL V V_QM VAL W X X1 X2 +%token XC Y Y1 Y2 YC Z ZL ZLEN ZW + + /* Booleans */ + +%token YES NO + +%token BOOL +%token POSINT +%token FLOAT +%token STRING + +%start hyp_file + +%% + +/* + * Note: + * Use left recursion when parsing board perimeter and nets. + * When using left recursion cpu time is linear with board size. + * When using right recursion we run out of memory on large boards. + * (Typical error message: line xxx: memory exhausted at 'yyy' ) + */ + + /* + hyperlynx file sections: + + board_file + version + data_mode* + units + plane_sep* + board* + stackup* + devices + supplies* + padstack* + net + net_class* + end + + * = optional section + + */ + +hyp_file + : hyp_file hyp_section + | hyp_section ; + +hyp_section + : board_file + | version + | data_mode + | units + | plane_sep + | board + | stackup + | devices + | supplies + | padstack + | net + | netclass + | end + | key + | '{' error '}' ; + + /* board_file */ + +board_file + : '{' BOARD_FILE { if (hyp->exec_board_file(h)) YYERROR; } '}' ; + + /* version */ + +version + : '{' VERSION '=' FLOAT { h.vers = yylval.floatval; } '}' { if (hyp->exec_version(h)) YYERROR; } ; + + /* data_mode */ + +data_mode + : '{' DATA_MODE '=' mode '}' { if (hyp->exec_data_mode(h)) YYERROR; }; + +mode + : SIMPLIFIED { h.detailed = false; } + | DETAILED { h.detailed = true; } ; + + /* units */ + +units + : '{' UNITS '=' unit_system metal_thickness_unit '}' { if (hyp->exec_units(h)) YYERROR; } ; + +unit_system + : ENGLISH { h.unit_system_english = true; } + | METRIC { h.unit_system_english = false; }; + +metal_thickness_unit + : WEIGHT { h.metal_thickness_weight = true; } + | LENGTH { h.metal_thickness_weight = false; } ; + + /* plane_sep */ +plane_sep + : '{' PLANE_SEP '=' FLOAT { h.default_plane_separation = yylval.floatval; } '}' { if (hyp->exec_plane_sep(h)) YYERROR; } ; + + /* board */ + +board + : '{' BOARD board_paramlist '}' + | '{' BOARD '}' ; + +board_paramlist + : board_paramlist board_param + | board_param ; + +board_param + : perimeter_segment + | perimeter_arc + | board_attribute + | '(' error ')' ; + +perimeter_segment + : '(' PERIMETER_SEGMENT coord_line ')' { if (hyp->exec_perimeter_segment(h)) YYERROR; } ; + +perimeter_arc + : '(' PERIMETER_ARC coord_arc ')' { if (hyp->exec_perimeter_arc(h)) YYERROR; } ; + +board_attribute + : '(' A N '=' STRING { h.name = yylval.strval; } V '=' STRING { h.value = yylval.strval; } ')' { if (hyp->exec_board_attribute(h)) YYERROR; } ; + + /* stackup */ + +stackup + : '{' STACKUP stackup_paramlist '}' ; + +stackup_paramlist + : stackup_paramlist stackup_param + | stackup_param ; + +stackup_param + : options + | signal + | dielectric + | plane + | '(' error ')' ; + +options + : '(' OPTIONS options_params { if (hyp->exec_options(h)) YYERROR; } ; + +options_params + : USE_DIE_FOR_METAL '=' BOOL { h.use_die_for_metal = yylval.boolval; } ')' + | ')' + ; + +signal + : '(' SIGNAL { new_record(); } signal_paramlist ')' { if (hyp->exec_signal(h)) YYERROR; } ; + +signal_paramlist + : signal_paramlist signal_param + | signal_param ; + +signal_param + : thickness + | plating_thickness + | C '=' FLOAT { h.bulk_resistivity = yylval.floatval; h.bulk_resistivity_set = true; } + | bulk_resistivity + | temperature_coefficient + | epsilon_r + | loss_tangent + | layer_name + | material_name + | plane_separation ; + +dielectric + : '(' DIELECTRIC { new_record(); } dielectric_paramlist ')' { if (hyp->exec_dielectric(h)) YYERROR; } ; + +dielectric_paramlist + : dielectric_paramlist dielectric_param + | dielectric_param ; + +dielectric_param + : thickness + | C '=' FLOAT { h.epsilon_r = yylval.floatval; h.epsilon_r_set = true; } + | epsilon_r + | loss_tangent + | conformal + | prepreg + | layer_name + | material_name + ; + +plane + : '(' PLANE { new_record(); } plane_paramlist ')' { if (hyp->exec_plane(h)) YYERROR; } ; + +plane_paramlist + : plane_paramlist plane_param + | plane_param ; + +plane_param + : thickness + | C '=' FLOAT { h.bulk_resistivity = yylval.floatval; h.bulk_resistivity_set = true; } + | bulk_resistivity + | temperature_coefficient + | epsilon_r + | loss_tangent + | layer_name + | material_name + | plane_separation ; + +thickness + : T '=' FLOAT { h.thickness = yylval.floatval; h.thickness_set = true; } + +plating_thickness + : P '=' FLOAT { h.plating_thickness = yylval.floatval; h.plating_thickness_set = true; } + +bulk_resistivity + : BR '=' FLOAT { h.bulk_resistivity = yylval.floatval; h.bulk_resistivity_set = true; } + +temperature_coefficient + : TC '=' FLOAT { h.temperature_coefficient = yylval.floatval; h.temperature_coefficient_set = true; } + +epsilon_r + : ER '=' FLOAT { h.epsilon_r = yylval.floatval; h.epsilon_r_set = true; } + +loss_tangent + : LT '=' FLOAT { h.loss_tangent = yylval.floatval; h.loss_tangent_set = true; } + +layer_name + : L '=' STRING { h.layer_name = yylval.strval; h.layer_name_set = true; } + +material_name + : M '=' STRING { h.material_name = yylval.strval; h.material_name_set = true; } + +plane_separation + : PS '=' FLOAT { h.plane_separation = yylval.floatval; h.plane_separation_set = true; } + +conformal + : CO_QM '=' BOOL { h.conformal = yylval.boolval; h.conformal_set = true; } + +prepreg + : PR_QM '=' BOOL { h.prepreg = yylval.boolval; h.prepreg_set = true; } + + /* devices */ + +devices + : '{' DEVICES device_list '}' + | '{' DEVICES '}' ; + +device_list + : device_list device + | device ; + +device + : '(' { new_record(); } STRING { h.device_type = yylval.strval; } REF '=' STRING { h.ref = yylval.strval; } device_paramlist ')' { if (hyp->exec_devices(h)) YYERROR; } + | '(' error ')' ; + +device_paramlist + : name device_value + | device_value + ; + +device_value + : value device_layer + | device_layer + ; + +device_layer + : layer_name package + | layer_name + ; + +name + : NAME '=' STRING { h.name = yylval.strval; h.name_set = true; } ; + +value + : value_float + | value_string + ; + +value_float + : VAL '=' FLOAT { h.value_float = yylval.floatval; h.value_float_set = true; } ; + +value_string + : VAL '=' STRING { h.value_string = yylval.strval; h.value_string_set = true; } ; + +package + : PKG '=' STRING { h.package = yylval.strval; h.package_set = true; } ; + + /* supplies */ + +supplies + : '{' SUPPLIES supply_list '}' ; + +supply_list + : supply_list supply + | supply ; + +supply + : '(' S name value_float voltage_spec conversion ')' { if (hyp->exec_supplies(h)) YYERROR; } + | '(' error ')' ; + +voltage_spec + : V_QM '=' BOOL { h.voltage_specified = yylval.boolval; } ; + +conversion + : C_QM '=' BOOL { h.conversion = yylval.boolval; } + + /* padstack */ + +padstack + : '{' PADSTACK { new_record(); } '=' STRING { h.padstack_name = yylval.strval; h.padstack_name_set = true; } drill_size '}' { if (hyp->exec_padstack_end(h)) YYERROR; } ; + +drill_size + : ',' FLOAT { h.drill_size = yylval.floatval; h.drill_size_set = true; } padstack_list + | ',' padstack_list ; + | padstack_list ; + +padstack_list + : padstack_list padstack_def + | padstack_def ; + +padstack_def + : '(' STRING { h.layer_name = yylval.strval; h.layer_name_set = true; } ',' pad_shape pad_coord pad_type { if (hyp->exec_padstack_element(h)) YYERROR; new_record(); } + | '(' error ')' ; + +pad_shape + : FLOAT { h.pad_shape = yylval.floatval; } ',' + | ',' { h.pad_shape = -1; } /* Workaround: Altium sometimes prints an empty pad shape */ + ; + +pad_coord + : FLOAT { h.pad_sx = yylval.floatval; } ',' FLOAT { h.pad_sy = yylval.floatval; } ',' FLOAT { h.pad_angle = yylval.floatval; } + +pad_type + : ')' + | ',' M ')' { h.pad_type = PAD_TYPE_METAL; h.pad_type_set = true; } + | ',' A ')' { h.pad_type = PAD_TYPE_ANTIPAD; h.pad_type_set = true; } + | ',' FLOAT { h.thermal_clear_shape = yylval.floatval; } + ',' FLOAT { h.thermal_clear_sx = yylval.floatval; } + ',' FLOAT { h.thermal_clear_sy = yylval.floatval; } + ',' FLOAT { h.thermal_clear_angle = yylval.floatval; } + ',' T ')' { h.pad_type = PAD_TYPE_THERMAL_RELIEF; h.pad_type_set = true; } + ; + + /* net */ + +net + : '{' NET '=' STRING { h.net_name = yylval.strval; if (hyp->exec_net(h)) YYERROR; } net_def '}' ; + +net_def + : plane_separation { if (hyp->exec_net_plane_separation(h)) YYERROR; } net_subrecord_list + | net_subrecord_list ; + +net_subrecord_list + : net_subrecord_list net_subrecord + | net_subrecord ; + +net_subrecord + : seg + | arc + | via + | pin + | pad + | useg + | polygon + | polyvoid + | polyline + | net_attribute + | '(' error ')' + | '{' error '}' + ; + +seg + : '(' SEG { new_record(); } coord_line width layer_name ps_lps_param { if (hyp->exec_seg(h)) YYERROR; } ; + +arc + : '(' ARC { new_record(); } coord_arc width layer_name ps_lps_param { if (hyp->exec_arc(h)) YYERROR; } ; + +ps_lps_param + : plane_separation lps_param + | lps_param + ; + +lps_param + : left_plane_separation ')' + | ')' + ; + +width + : W '=' FLOAT { h.width = yylval.floatval; h.width_set = true; } ; + +left_plane_separation + : LPS '=' FLOAT { h.left_plane_separation = yylval.floatval; h.left_plane_separation_set = true; } ; + +via + : '(' VIA { new_record(); } coord_point via_new_or_old_style + ; + +via_new_or_old_style + : via_new_style + | via_old_style + ; + +via_new_style + : via_new_style_l1_param { if (hyp->exec_via(h)) YYERROR; } ; + +via_new_style_l1_param + : layer1_name via_new_style_l2_param + | via_new_style_l2_param + ; + +via_new_style_l2_param + : layer2_name via_new_style_padstack_param + | via_new_style_padstack_param + ; + +via_new_style_padstack_param + : padstack_name ')' + ; + +padstack_name + : P '=' STRING { h.padstack_name = yylval.strval; h.padstack_name_set = true; } ; + +layer1_name + : L1 '=' STRING { h.layer1_name = yylval.strval; h.layer1_name_set = true; } ; + +layer2_name + : L2 '=' STRING { h.layer2_name = yylval.strval; h.layer2_name_set = true; } ; + +via_old_style + : D '=' FLOAT { h.drill_size = yylval.floatval; } /* deprecated hyperlynx v1.x VIA format */ + layer1_name + layer2_name + S1 '=' STRING { h.pad1_shape = yylval.strval; } + S1X '=' FLOAT { h.pad1_sx = yylval.floatval; } + S1Y '=' FLOAT { h.pad1_sy = yylval.floatval; } + A1 '=' FLOAT { h.pad1_angle = yylval.floatval; } + S2 '=' STRING { h.pad2_shape = yylval.strval; } + S2X '=' FLOAT { h.pad2_sx = yylval.floatval; } + S2Y '=' FLOAT { h.pad2_sy = yylval.floatval; } + A2 '=' FLOAT { h.pad2_angle = yylval.floatval; } + ')' { if (hyp->exec_via_v1(h)) YYERROR; } ; + ; + +pin + : '(' PIN { new_record(); } coord_point pin_reference pin_param { if (hyp->exec_pin(h)) YYERROR; } ; + +pin_param + : padstack_name pin_function_param + | pin_function_param + ; + +pin_function_param + : pin_function ')' + | ')' + ; + +pin_reference + : R '=' STRING { h.pin_reference = yylval.strval; h.pin_reference_set = true; } ; + +pin_function + : F '=' SIM_OUT { h.pin_function = PIN_SIM_OUT; h.pin_function_set = true; } + | F '=' SIM_IN { h.pin_function = PIN_SIM_IN; h.pin_function_set = true; } + | F '=' SIM_BOTH { h.pin_function = PIN_SIM_BOTH; h.pin_function_set = true; } + ; + +pad + : '(' PAD { new_record(); } /* deprecated hyperlynx v1.x only */ + coord_point + layer_name + S '=' STRING { h.pad1_shape = yylval.strval; } + SX '=' FLOAT { h.pad1_sx = yylval.floatval; } + SY '=' FLOAT { h.pad1_sy = yylval.floatval; } + A '=' FLOAT { h.pad1_angle = yylval.floatval; } + ')' { if (hyp->exec_pad(h)) YYERROR; } ; + ; + +useg + : '(' USEG { new_record(); } coord_point1 layer1_name coord_point2 layer2_name useg_param { if (hyp->exec_useg(h)) YYERROR; } ; + +useg_param + : useg_stackup + | useg_impedance + ; + +useg_stackup + : ZL '=' STRING { h.zlayer_name = yylval.strval; h.zlayer_name_set = true; } + ZW '=' FLOAT { h.width = yylval.floatval; } + ZLEN '=' FLOAT { h.length = yylval.floatval; } + ')' + ; + +useg_impedance + : Z '=' FLOAT { h.impedance = yylval.floatval; h.impedance_set = true; } + D '=' FLOAT { h.delay = yylval.floatval; } + useg_resistance; + +useg_resistance + : R '=' FLOAT { h.resistance = yylval.floatval; h.resistance_set = true;} + ')' + | ')' + ; + +polygon + : '{' POLYGON { new_record(); } polygon_param_list coord_point { if (hyp->exec_polygon_begin(h)) YYERROR; } + lines_and_curves '}' { if (hyp->exec_polygon_end(h)) YYERROR; } ; + +polygon_param_list + : polygon_param_list polygon_param + | polygon_param + ; + +polygon_param + : layer_name + | width + | polygon_type + | polygon_id + ; + +polygon_id + : ID '=' POSINT { h.id = yylval.intval; h.id_set = true; } /* polygon id is a non-negative integer */ + ; + +polygon_type + : T '=' POUR { h.polygon_type = POLYGON_TYPE_POUR; h.polygon_type_set = true; } + | T '=' PLANE { h.polygon_type = POLYGON_TYPE_PLANE; h.polygon_type_set = true; } + | T '=' COPPER { h.polygon_type = POLYGON_TYPE_COPPER; h.polygon_type_set = true; } + ; + +polyvoid + : '{' POLYVOID { new_record(); } polygon_id coord_point { if (hyp->exec_polyvoid_begin(h)) YYERROR; } + lines_and_curves '}' { if (hyp->exec_polyvoid_end(h)) YYERROR; } ; + +polyline + : '{' POLYLINE { new_record(); } polygon_param_list coord_point { if (hyp->exec_polyline_begin(h)) YYERROR; } + lines_and_curves '}' { if (hyp->exec_polyline_end(h)) YYERROR; } ; + +lines_and_curves + : lines_and_curves line_or_curve + | line_or_curve + ; + +line_or_curve + : line + | curve + | '(' error ')' + ; + +line + : '(' LINE { new_record(); } coord_point ')' { if (hyp->exec_line(h)) YYERROR; } ; + +curve + : '(' CURVE { new_record(); } coord_arc ')' { if (hyp->exec_curve(h)) YYERROR; } ; + +net_attribute + : '(' A N '=' STRING { h.name = yylval.strval; } V '=' STRING { h.value = yylval.strval; } ')' { if (hyp->exec_net_attribute(h)) YYERROR; } ; + + /* net class */ + +netclass + : '{' NET_CLASS '=' STRING { h.net_class_name = yylval.strval; if (hyp->exec_net_class(h)) YYERROR; } netclass_subrecords ; + +netclass_subrecords + : netclass_paramlist '}' + | '}' + ; + +netclass_paramlist + : netclass_paramlist netclass_param + | netclass_param + ; + +netclass_param + : netclass_attribute + | net_name + | '(' error ')' + ; + +net_name + : '(' N N '=' STRING { h.net_name = yylval.strval; } ')' { if (hyp->exec_net_class_element(h)) YYERROR; } ; + +netclass_attribute + : '(' A N '=' STRING { h.name = yylval.strval; } V '=' STRING { h.value = yylval.strval; } ')' { if (hyp->exec_net_class_attribute(h)) YYERROR; } ; + + /* end */ + +end + : '{' END '}' { if (hyp->exec_end(h)) YYERROR; } ; + + /* key */ + +key + : '{' KEY '=' STRING { h.key = yylval.strval; } '}' { if (hyp->exec_key(h)) YYERROR; } ; + + /* coordinates */ + +coord_point + : X '=' FLOAT { h.x = yylval.floatval; } Y '=' FLOAT { h.y = yylval.floatval; } ; + +coord_point1 + : X1 '=' FLOAT { h.x1 = yylval.floatval; } Y1 '=' FLOAT { h.y1 = yylval.floatval; } ; + +coord_point2 + : X2 '=' FLOAT { h.x2 = yylval.floatval; } Y2 '=' FLOAT { h.y2 = yylval.floatval; } ; + +coord_line + : coord_point1 coord_point2 ; + +coord_arc + : coord_line XC '=' FLOAT { h.xc = yylval.floatval; } YC '=' FLOAT { h.yc = yylval.floatval; } R '=' FLOAT { h.r = yylval.floatval; } ; + +%% + +/* + * Supporting C routines + */ + +void yyerror(HypFile::Hyp *hyp, const char *msg) +{ + std::ostringstream err_msg; + + err_msg << "line " << yylineno << ": " << msg << " at '" << yytext << "'"; + hyp->error(err_msg.str()); +} + +void yyprint(FILE *file, int type, YYSTYPE value) +{ + if (type == STRING) + fprintf (file, "%s", value.strval); + else if (type == FLOAT) + fprintf (file, "%g", value.floatval); + else if (type == BOOL) + fprintf (file, "%i", value.boolval); + return; +} + +/* + * reset parse_param struct at beginning of record + */ + +void new_record() +{ + h.vers = 0; + h.detailed = false; + h.unit_system_english = false; + h.metal_thickness_weight = false; + h.default_plane_separation = 0; + h.use_die_for_metal = false; + h.bulk_resistivity = 0; + h.conformal = false; + h.epsilon_r = 0; + h.layer_name.clear(); + h.loss_tangent = 0; + h.material_name.clear(); + h.plane_separation = 0; + h.plating_thickness = 0; + h.prepreg = false; + h.temperature_coefficient = 0; + h.thickness = 0; + h.bulk_resistivity_set = false; + h.conformal_set = false; + h.epsilon_r_set = false; + h.layer_name_set = false; + h.loss_tangent_set = false; + h.material_name_set = false; + h.plane_separation_set = false; + h.plating_thickness_set = false; + h.prepreg_set = false; + h.temperature_coefficient_set = false; + h.thickness_set = false; + h.device_type.clear(); + h.ref.clear(); + h.value_float = 0; + h.value_string.clear(); + h.package.clear(); + h.name_set = false; + h.value_float_set = false; + h.value_string_set = false; + h.package_set = false; + h.voltage_specified = false; + h.conversion = false; + h.padstack_name.clear(); + h.drill_size = 0; + h.pad_shape = 0; + h.pad_sx = 0; + h.pad_sy = 0; + h.pad_angle = 0; + h.thermal_clear_shape = 0; + h.thermal_clear_sx = 0; + h.thermal_clear_sy = 0; + h.thermal_clear_angle = 0; + h.pad_type = PAD_TYPE_METAL; + h.padstack_name_set = false; + h.drill_size_set = false; + h.pad_type_set = false; + h.width = 0; + h.left_plane_separation = 0; + h.width_set = false; + h.left_plane_separation_set = false; + h.layer1_name.clear(); + h.layer1_name_set = false; + h.layer2_name.clear(); + h.layer2_name_set = false; + h.pad1_shape.clear(); + h.pad1_sx = 0; + h.pad1_sy = 0; + h.pad1_angle = 0; + h.pad2_shape.clear(); + h.pad2_sx = 0; + h.pad2_sy = 0; + h.pad2_angle = 0; + h.pin_reference.clear(); + h.pin_reference_set = false; + h.pin_function = PIN_SIM_BOTH; + h.pin_function_set = false; + h.zlayer_name.clear(); + h.zlayer_name_set = false; + h.length = 0; + h.impedance = 0; + h.impedance_set = false; + h.delay = 0; + h.resistance = 0; + h.resistance_set = false; + h.id = -1; + h.id_set = false; + h.polygon_type = POLYGON_TYPE_PLANE; + h.polygon_type_set = false; + h.net_class_name.clear(); + h.net_name.clear(); + h.key.clear(); + h.name.clear(); + h.value.clear(); + h.x = 0; + h.y = 0; + h.x1 = 0; + h.y1 = 0; + h.x2 = 0; + h.y2 = 0; + h.xc = 0; + h.yc = 0; + h.r = 0; + + return; +} + +/* not truncated */ Index: hyp/scan.ll =================================================================== --- hyp/scan.ll (nonexistent) +++ hyp/scan.ll (revision 4710) @@ -0,0 +1,371 @@ + +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +%option noyywrap nodefault yylineno debug + +%{ +#include +#include "parse.h" +#include "parser.h" + +/* copy a string between quotes */ +char *strunquote(const char *); + +/* remember hyperlynx file section we're in */ +int section = -1; + +%} + + /* + * The scanner knows five states: INITIAL, STATE_STRING, STATE_POSINT, STATE_FLOAT and STATE_COMMENT + * + * In state INITIAL the scanner recognizes: + * - punctuation (such as {}()=, ) + * - keywords (such as VERSION, BOARD, NET), + * - strings (both between double quotes " and unquoted), + * - and floating point numbers (with optional suffix, eg. 10 uF), + * + * In STATE_STRING the scanner recognizes punctuation and strings only. + * This avoids unquoted strings being interpreted as numbers, or keywords. + * + * In STATE_POSINT the scanner recognizes a positive integer. + * + * In STATE_FLOAT the scanner recognizes a floating point number (without suffix). + * + * In STATE_COMMENT the scanner discards all text up to the next + * right brace } , and then continues in state INITIAL. + * + */ + +%x STATE_STRING STATE_POSINT STATE_FLOAT STATE_COMMENT STATE_COMMENT_EOL + + /* whitespace: space, tab, vertical tab, form feed */ +WS [ \t\v\f] + + /* accept windows and unix newlines */ +NEWLINE [\r\n]+ + + /* + * lines with an asterisk in the first column are comments + */ +COMMENT ^\*[^\n\r]*[\n\r]+ + + /* Left-hand side of an assignment: check whether next token is equals sign */ +LHS [ \t\v\f]*"=" + + /* + * Positive integer + */ + +POSINT [0-9]+ + + /* + * Floating point numbers + */ + + /* ordinary floating point numbers */ +SIMPLE_FLOAT [-+]?([0-9]+"."[0-9]*|"."?[0-9]+)([Ee][-+]?[0-9]+)? + + /* floating point numbers with suffix, e,g. pF, nH */ +FLOAT_SUFFIX [A-Za-z]*{WS}+ +FLOAT_YOTTA {SIMPLE_FLOAT}{WS}*"Y"{FLOAT_SUFFIX} +FLOAT_ZETA {SIMPLE_FLOAT}{WS}*"Z"{FLOAT_SUFFIX} +FLOAT_EXA {SIMPLE_FLOAT}{WS}*"E"{FLOAT_SUFFIX} +FLOAT_PETA {SIMPLE_FLOAT}{WS}*"P"{FLOAT_SUFFIX} +FLOAT_TERA {SIMPLE_FLOAT}{WS}*"T"{FLOAT_SUFFIX} +FLOAT_GIGA {SIMPLE_FLOAT}{WS}*"G"{FLOAT_SUFFIX} +FLOAT_MEGA {SIMPLE_FLOAT}{WS}*"M"{FLOAT_SUFFIX} +FLOAT_KILO {SIMPLE_FLOAT}{WS}*[Kk]{FLOAT_SUFFIX} +FLOAT_MILLI {SIMPLE_FLOAT}{WS}*"m"{FLOAT_SUFFIX} +FLOAT_MICRO {SIMPLE_FLOAT}{WS}*[uU]{FLOAT_SUFFIX} +FLOAT_NANO {SIMPLE_FLOAT}{WS}*[nN]{FLOAT_SUFFIX} +FLOAT_PICO {SIMPLE_FLOAT}{WS}*[pP]{FLOAT_SUFFIX} +FLOAT_FEMTO {SIMPLE_FLOAT}{WS}*[fF]{FLOAT_SUFFIX} +FLOAT_ATTO {SIMPLE_FLOAT}{WS}*"a"{FLOAT_SUFFIX} +FLOAT_ZEPTO {SIMPLE_FLOAT}{WS}*"z"{FLOAT_SUFFIX} +FLOAT_YOCTO {SIMPLE_FLOAT}{WS}*"y"{FLOAT_SUFFIX} + + /* + * Strings + */ + + /* an unquoted string */ +STRING [^ \t\v\f\r\n\{\}\(\)=\"]+ + + /* a string enclosed in double quotes " */ +QUOTED_STRING \"([^\"\n]|\"\")*\" + +%% + + /* When in STATE_COMMENT skip all comment until next right brace */ +{ +[^\}]* { BEGIN INITIAL; /* skip all comment until next right brace */ } +} + + /* When in STATE_COMMENT_EOL skip all comment until end-of-line */ +{ +[^\r\n]*{NEWLINE}+ { BEGIN INITIAL; /* skip all comment until next end-of-line */ } +} + + + /* skip comments and whitespace */ +<*>{ + + {COMMENT} { /* skip comments */ } + + {WS}+ { /* skip whitespace */ } + + {NEWLINE}+ { /* skip newlines */ } + +} + + /* + * Hyperlynx keywords + */ + + /* Sections */ + +"BOARD_FILE" {section = BOARD_FILE; return BOARD_FILE;} +"VERSION" {section = VERSION; return VERSION;} +"DATA_MODE" {section = DATA_MODE; return DATA_MODE;} +"UNITS" {section = UNITS; return UNITS;} +"PLANE_SEP" {section = PLANE_SEP; return PLANE_SEP;} +"BOARD" {section = BOARD; BEGIN STATE_COMMENT_EOL; return BOARD;} +"STACKUP" {section = STACKUP; BEGIN STATE_COMMENT_EOL; return STACKUP;} +"DEVICES" {section = DEVICES; BEGIN STATE_COMMENT_EOL; return DEVICES;} +"SUPPLIES" {section = SUPPLIES; BEGIN STATE_COMMENT_EOL; return SUPPLIES;} +"PADSTACK" {section = PADSTACK; BEGIN STATE_STRING; return PADSTACK;} +"NET" {section = NET; BEGIN STATE_STRING; return NET;} +"NET_CLASS" {section = NET_CLASS; return NET_CLASS;} +"END" {section = END; return END;} +"KEY" {section = KEY; return KEY;} + + /* Keywords */ + +"A" {return A;} +"ARC" {return ARC;} +"COPPER" {return COPPER;} +"CURVE" {return CURVE;} +"DETAILED" {if (section == DATA_MODE) BEGIN STATE_COMMENT; return DETAILED;} +"DIELECTRIC" {return DIELECTRIC;} +"ENGLISH" {return ENGLISH;} +"LENGTH" {if (section == UNITS) BEGIN STATE_COMMENT; return LENGTH;} +"LINE" {return LINE;} +"METRIC" {return METRIC;} +"M" {return M;} +"N" {return N;} +"OPTIONS" {return OPTIONS;} +"PAD" {return PAD;} +"PERIMETER_ARC" {return PERIMETER_ARC;} +"PERIMETER_SEGMENT" {return PERIMETER_SEGMENT;} +"PIN" {return PIN;} +"PLANE" {return PLANE;} +"POLYGON" {return POLYGON;} +"POLYLINE" {return POLYLINE;} +"POLYVOID" {return POLYVOID;} +"POUR" {return POUR;} +"S" {return S;} +"T" {return T;} +"SEG" {return SEG;} +"SIGNAL" {return SIGNAL;} +"SIMPLIFIED" {if (section == DATA_MODE) BEGIN STATE_COMMENT; return SIMPLIFIED; } +"SIM_BOTH" {return SIM_BOTH;} +"SIM_IN" {return SIM_IN;} +"SIM_OUT" {return SIM_OUT;} +"USEG" {return USEG;} +"VIA" {return VIA;} +"WEIGHT" {if (section == UNITS) BEGIN STATE_COMMENT; return WEIGHT;} + + /* Assignments */ + +"A"/{LHS} {return A;} +"A1"/{LHS} {return A1;} +"A2"/{LHS} {return A2;} +"BR"/{LHS} {return BR;} +"C"/{LHS} {return C;} +"C?"/{LHS} {return C_QM;} +"CO?"/{LHS} {return CO_QM;} +"D"/{LHS} {return D;} +"ER"/{LHS} {return ER;} +"F"/{LHS} {return F;} +"ID"/{LHS} {BEGIN STATE_POSINT; return ID;} +"L"/{LHS} {BEGIN STATE_STRING; return L;} +"L1"/{LHS} {BEGIN STATE_STRING; return L1;} +"L2"/{LHS} {BEGIN STATE_STRING; return L2;} +"LPS"/{LHS} {return LPS;} +"LT"/{LHS} {return LT;} +"M"/{LHS} {BEGIN STATE_STRING; return M;} +"N"/{LHS} {BEGIN STATE_STRING; return N;} +"NAME"/{LHS} {BEGIN STATE_STRING; return NAME;} + /* P is used as "plating thickness" in "stackup/signal" and as "padstack" in "net/via" */ +"P"/{LHS} {if (section == NET) BEGIN STATE_STRING; return P;} +"PKG"/{LHS} {BEGIN STATE_STRING; return PKG;} +"PR?"/{LHS} {return PR_QM;} +"PS"/{LHS} {return PS;} +"R"/{LHS} {return R;} +"REF"/{LHS} {BEGIN STATE_STRING; return REF;} +"S"/{LHS} {BEGIN STATE_STRING; return S;} +"SX"/{LHS} {return SX;} +"SY"/{LHS} {return SY;} +"S1"/{LHS} {BEGIN STATE_STRING; return S1;} +"S1X"/{LHS} {return S1X;} +"S1Y"/{LHS} {return S1Y;} +"S2"/{LHS} {BEGIN STATE_STRING; return S2;} +"S2X"/{LHS} {return S2X;} +"S2Y"/{LHS} {return S2Y;} +"T"/{LHS} {return T;} +"TC"/{LHS} {return TC;} +"USE_DIE_FOR_METAL"/{LHS} {return USE_DIE_FOR_METAL;} +"V"/{LHS} {BEGIN STATE_STRING; return V;} +"V?"/{LHS} {return V_QM;} +"VAL"/{LHS} {return VAL;} +"W"/{LHS} {return W;} +"X"/{LHS} {return X;} +"X1"/{LHS} {return X1;} +"X2"/{LHS} {return X2;} +"XC"/{LHS} {return XC;} +"Y"/{LHS} {return Y;} +"Y1"/{LHS} {return Y1;} +"Y2"/{LHS} {return Y2;} +"YC"/{LHS} {return YC;} +"Z"/{LHS} {return Z;} +"ZL"/{LHS} {return ZL;} +"ZLEN"/{LHS} {return ZLEN;} +"ZW"/{LHS} {return ZW;} + + /* Booleans */ + +"YES"|"yes" {yylval.boolval = 1; return BOOL; } +"NO"|"no" {yylval.boolval = 0; return BOOL; } + + /* Floats */ + + /* ordinary floating point numbers */ +{SIMPLE_FLOAT} {yylval.floatval = strtod(yytext, NULL); return FLOAT;} + + /* floating point numbers with suffix, e,g. pF, nH */ +{FLOAT_YOTTA} {yylval.floatval = strtod(yytext, NULL) * 1e24; return FLOAT;} +{FLOAT_ZETA} {yylval.floatval = strtod(yytext, NULL) * 1e21; return FLOAT;} +{FLOAT_EXA} {yylval.floatval = strtod(yytext, NULL) * 1e18; return FLOAT;} +{FLOAT_PETA} {yylval.floatval = strtod(yytext, NULL) * 1e15; return FLOAT;} +{FLOAT_TERA} {yylval.floatval = strtod(yytext, NULL) * 1e12; return FLOAT;} +{FLOAT_GIGA} {yylval.floatval = strtod(yytext, NULL) * 1e9; return FLOAT;} +{FLOAT_MEGA} {yylval.floatval = strtod(yytext, NULL) * 1e6; return FLOAT;} +{FLOAT_KILO} {yylval.floatval = strtod(yytext, NULL) * 1e3; return FLOAT;} +{FLOAT_MILLI} {yylval.floatval = strtod(yytext, NULL) * 1e-3; return FLOAT;} +{FLOAT_MICRO} {yylval.floatval = strtod(yytext, NULL) * 1e-6; return FLOAT;} +{FLOAT_NANO} {yylval.floatval = strtod(yytext, NULL) * 1e-9; return FLOAT;} +{FLOAT_PICO} {yylval.floatval = strtod(yytext, NULL) * 1e-12; return FLOAT;} +{FLOAT_FEMTO} {yylval.floatval = strtod(yytext, NULL) * 1e-15; return FLOAT;} +{FLOAT_ATTO} {yylval.floatval = strtod(yytext, NULL) * 1e-18; return FLOAT;} +{FLOAT_ZEPTO} {yylval.floatval = strtod(yytext, NULL) * 1e-21; return FLOAT;} +{FLOAT_YOCTO} {yylval.floatval = strtod(yytext, NULL) * 1e-24; return FLOAT;} + + /* floating point numbers in VERSION and PLANE_SEP have no suffix and are followed by optional comments */ +{ +{SIMPLE_FLOAT} {yylval.floatval = strtod(yytext, NULL); BEGIN STATE_COMMENT; return FLOAT;} +} + + /* A positive integer is used only in polygon/polyline/polyvoid "ID = posint" */ +{ +{POSINT} { BEGIN INITIAL; yylval.intval = atoi(yytext); return POSINT; } +} + + + /* + * This is a workaround for syntactically incorrect .hyp files. + * We accept the following constructs as representing an empty string: + * NAME= L1=somelayer + * NAME= ) + * NAME= } + */ +{ +([A-Z][A-Z1-2_]*{WS}*"="|")"|"}") { yyless(0); BEGIN INITIAL; yylval.strval = strdup(""); return STRING; } /* emit empty string and reprocess */ +} + +<*>{ + + "{" {return '{';} + + "}" {BEGIN STATE_COMMENT_EOL; return '}';} + + "(" {if (section == PADSTACK) BEGIN STATE_STRING; return '(';} + + /* allow for comment after the closing bracket ) */ + ")" {BEGIN STATE_COMMENT_EOL; return ')';} + + "," {return ',';} + + "=" {if ((section == VERSION) || (section == PLANE_SEP)) BEGIN STATE_FLOAT; return '=';} + + /* string */ + {STRING} { + /* + * Commas are not allowed in strings in the padstack section + * unless the string is enclosed in double quotes ("). + */ + + if ((section == PADSTACK) && strchr(yytext, ',')) + REJECT + else + { + BEGIN INITIAL; + yylval.strval = strdup(yytext); + return STRING; + } + } + + /* string in double quotes */ + {QUOTED_STRING} {BEGIN INITIAL; yylval.strval = strunquote(yytext); return STRING;} + + <> {yyterminate();} + + /* have bison catch all unrecognized characters with parse errors */ + . {return yytext[0];} + +} + +%% + + /* + * copy a quoted string. + * e.g. "data 0" -> data 0 + * a double quote inside the string can be escaped by writing two consecutive double quotes + * e.g. "net ""hi""" -> net "hi" + */ + + char *strunquote(const char *src) + { + char* dst; + size_t len = strlen(src) + 1; + dst = (char *)malloc(len); + if (dst != NULL) + { + char* p = (char *)src + 1; /* first char after initial quote */ + char* q = dst; + do + if (*p == '"') p++; + while ((*q++ = *p++) != '\0'); + } + return dst; + } + + /* not truncated */