%{ // OpenSTA, Static Timing Analyzer // Copyright (c) 2024, Parallax Software, Inc. // // 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 . #include #include #include "util/FlexDisableRegister.hh" #include "liberty/LibertyParser.hh" #include "LibertyParse.hh" #define YY_NO_INPUT #if defined(YY_FLEX_MAJOR_VERSION) \ && defined(YY_FLEX_MINOR_VERSION) \ && YY_FLEX_MAJOR_VERSION >=2 \ && (YY_FLEX_MINOR_VERSION > 5 \ || (YY_FLEX_MINOR_VERSION == 5 \ && defined(YY_FLEX_SUBMINOR_VERSION) \ && YY_FLEX_SUBMINOR_VERSION >= 31)) #define INCLUDE_SUPPORTED #endif static std::string string_buf; void libertyParseFlushBuffer() { YY_FLUSH_BUFFER; } %} /* %option debug */ %option noyywrap %option nounput %option never-interactive %x comment %x qstring DIGIT [0-9] ALPHA [a-zA-Z] FLOAT [-+]?(({DIGIT}+\.?{DIGIT}*)|(\.{DIGIT}+))([Ee][-+]?{DIGIT}+)? BLANK [ \t] BUS_LEFT [\[<] BUS_RIGHT [\]>] BUS_SUB {BUS_LEFT}{DIGIT}+{BUS_RIGHT} BUS_RANGE {BUS_LEFT}{DIGIT}+:{DIGIT}+{BUS_RIGHT} PIN_NAME ({ALPHA}|_)({ALPHA}|{DIGIT}|_)*!? BUS_NAME {PIN_NAME}({BUS_SUB}|{BUS_RANGE}) BUS_NAME2 {PIN_NAME}{BUS_SUB}({BUS_SUB}|{BUS_RANGE}) MIXED_NAME {BUS_NAME}_{PIN_NAME} HNAME ({PIN_NAME}|{BUS_NAME}|{MIXED_NAME})([\/.]({PIN_NAME}|{BUS_NAME}|{MIXED_NAME}))+ /* ocv_table_template(2D_ocv_template) */ /* leakage_power_unit : 1pW; */ /* default_operating_conditions : slow_100_3.00 ; */ /* revision : 1.0.17; */ /* default_wire_load : xc2v250-5_avg; */ TOKEN ({ALPHA}|{DIGIT}|_)({ALPHA}|{DIGIT}|[._\-])*(:({ALPHA}|{DIGIT}|_)+)? /* bus_naming_style : %s[%d] ; */ BUS_STYLE "%s"{BUS_LEFT}"%d"{BUS_RIGHT} PUNCTUATION [,\:;|(){}+*&!'=] TOKEN_END {PUNCTUATION}|[ \t\r\n] EOL \r?\n %% {PUNCTUATION} { return ((int) LibertyLex_text[0]); } {FLOAT}{TOKEN_END} { /* Push back the TOKEN_END character. */ yyless(LibertyLex_leng - 1); LibertyParse_lval.number = static_cast(strtod(LibertyLex_text, NULL)); return FLOAT; } {ALPHA}({ALPHA}|_|{DIGIT})*{TOKEN_END} { /* Push back the TOKEN_END character. */ yyless(LibertyLex_leng - 1); LibertyParse_lval.string = sta::stringCopy(LibertyLex_text); return KEYWORD; } {PIN_NAME}{TOKEN_END} | {BUS_NAME}{TOKEN_END} | {BUS_NAME2}{TOKEN_END} | {MIXED_NAME}{TOKEN_END} | {HNAME}{TOKEN_END} | {BUS_STYLE}{TOKEN_END} | {TOKEN}{TOKEN_END} { /* Push back the TOKEN_END character. */ yyless(LibertyLex_leng - 1); LibertyParse_lval.string = sta::stringCopy(LibertyLex_text); return STRING; } \\?{EOL} { sta::libertyIncrLine(); } "include_file"[ \t]*"(".+")"[ \t]*";"? { #ifdef INCLUDE_SUPPORTED if (sta::libertyInInclude()) sta::libertyParseError("nested include_file's are not supported"); else { char *filename = &yytext[strlen("include_file")]; /* Skip blanks between include_file and '('. */ while (isspace(*filename) && *filename != '\0') filename++; /* Skip '('. */ filename++; /* Skip blanks between '(' and filename. */ while (isspace(*filename) && *filename != '\0') filename++; char *filename_end = strpbrk(filename, ")"); if (filename_end == NULL) sta::libertyParseError("include_file missing ')'"); else { /* Trim trailing blanks. */ while (isspace(filename_end[-1]) && filename_end > filename) filename_end--; *filename_end = '\0'; sta::libertyIncludeBegin(filename); yypush_buffer_state(yy_create_buffer(nullptr, YY_BUF_SIZE)); BEGIN(INITIAL); } } #else sta::libertyParseError("include_file is not supported."); #endif } "/*" BEGIN(comment); /* Straight out of the flex man page. */ [^*\r\n]* /* eat anything that's not a '*' */ "*"+[^*/\r\n]* /* eat up '*'s not followed by '/'s */ {EOL} sta::libertyIncrLine(); "*"+"/" BEGIN(INITIAL); \" { string_buf.erase(); BEGIN(qstring); } \" { BEGIN(INITIAL); LibertyParse_lval.string = sta::stringCopy(string_buf.c_str()); return STRING; } {EOL} { LibertyParse_error("unterminated string constant"); BEGIN(INITIAL); LibertyParse_lval.string = sta::stringCopy(string_buf.c_str()); return STRING; } \\{EOL} { /* Line continuation. */ sta::libertyIncrLine(); } \\. { /* Escaped character. */ string_buf += '\\'; string_buf += LibertyLex_text[1]; } [^\\\r\n\"]+ { /* Anything but escape, return or double quote */ string_buf += LibertyLex_text; } <> { LibertyParse_error("unterminated string constant"); BEGIN(INITIAL); yyterminate(); } {BLANK}* {} /* Send out of bound characters to parser. */ . { return (int) LibertyLex_text[0]; } <> { #ifdef INCLUDE_SUPPORTED if (sta::libertyInInclude()) { sta::libertyIncludeEnd(); yypop_buffer_state(); } else #endif yyterminate(); } %%