diff options
Diffstat (limited to 'hyp2mat/lib/scan.ll')
-rw-r--r-- | hyp2mat/lib/scan.ll | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/hyp2mat/lib/scan.ll b/hyp2mat/lib/scan.ll new file mode 100644 index 0000000..3e07902 --- /dev/null +++ b/hyp2mat/lib/scan.ll @@ -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 <http://www.gnu.org/licenses/>. + */ + +%option noyywrap nodefault yylineno debug + +%{ +#include <stdlib.h> +#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 */ +<STATE_COMMENT>{ +[^\}]* { BEGIN INITIAL; /* skip all comment until next right brace */ } +} + + /* When in STATE_COMMENT_EOL skip all comment until end-of-line */ +<STATE_COMMENT_EOL>{ +[^\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 */ +<STATE_FLOAT>{ +{SIMPLE_FLOAT} {yylval.floatval = strtod(yytext, NULL); BEGIN STATE_COMMENT; return FLOAT;} +} + + /* A positive integer is used only in polygon/polyline/polyvoid "ID = posint" */ +<STATE_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= } + */ +<STATE_STRING>{ +([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;} + + <<EOF>> {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 */ |