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