/*
* 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 */