1 %option prefix="sdf"
2 %option never-interactive
3 %option nounput
4 %option noinput
5 
6 %{
7 /*
8  * Copyright (c) 2007-2019 Stephen Williams (steve@icarus.com)
9  *
10  *    This source code is free software; you can redistribute it
11  *    and/or modify it in source code form under the terms of the GNU
12  *    General Public License as published by the Free Software
13  *    Foundation; either version 2 of the License, or (at your option)
14  *    any later version.
15  *
16  *    This program is distributed in the hope that it will be useful,
17  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *    GNU General Public License for more details.
20  *
21  *    You should have received a copy of the GNU General Public License
22  *    along with this program; if not, write to the Free Software
23  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  */
25 
26 # include  "sdf_priv.h"
27 # include  "sdf_parse_priv.h"
28 # include  "sdf_parse.h"
29 # include  <stdlib.h>
30 # include  <string.h>
31 # include  <strings.h>
32 # include  <assert.h>
33 
34 static void process_quoted_string(void);
35 static int lookup_keyword(const char*text);
36 const char*sdf_parse_path = 0;
37 
yywrap(void)38 static int yywrap(void)
39 {
40       return 1;
41 }
42 
43 
44 # define yylval sdflval
45 %}
46 
47 %x CCOMMENT
48 %x COND_EDGE_ID
49 %x EDGE_ID
50 
51 %%
52 
53   /* Skip C++-style comments. */
54 "//".* { ; }
55 
56   /* Skip C-style comments. */
57 "/*"           { BEGIN(CCOMMENT); }
58 <CCOMMENT>.    { ; }
59 <CCOMMENT>\n   { sdflloc.first_line += 1; }
60 <CCOMMENT>"*/" { BEGIN(0); }
61 
62 [ \m\t] { /* Skip white space. */; }
63 
64   /* Count lines so that the parser can assign line numbers. */
65 \n { sdflloc.first_line += 1; }
66 
67   /* The other edge identifiers. */
68 <COND_EDGE_ID,EDGE_ID>"01"    {return K_01; }
69 <COND_EDGE_ID,EDGE_ID>"10"    {return K_10; }
70 <COND_EDGE_ID,EDGE_ID>"0"[zZ] {return K_0Z; }
71 <COND_EDGE_ID,EDGE_ID>[zZ]"1" {return K_Z1; }
72 <COND_EDGE_ID,EDGE_ID>"1"[zZ] {return K_1Z; }
73 <COND_EDGE_ID,EDGE_ID>[zZ]"0" {return K_Z0; }
74 <COND_EDGE_ID,EDGE_ID>[pP][oO][sS][eE][dD][gG][eE] {return K_POSEDGE; }
75 <COND_EDGE_ID,EDGE_ID>[nN][eE][gG][eE][dD][gG][eE] {return K_NEGEDGE; }
76 <COND_EDGE_ID>[cC][oO][nN][dD] {return K_COND; }
77 
78   /* Integer values */
79 [0-9]+ {
80       yylval.int_val = strtoul(yytext, 0, 10);
81       return INTEGER;
82 }
83 
84   /* Real values */
85 [0-9]+(\.[0-9]+)?([Ee][+-]?[0-9]+)? {
86       yylval.real_val = strtod(yytext, 0);
87       return REAL_NUMBER;
88 }
89 
90 ([a-zA-Z_]|(\\[^ \t\b\f\r\n]))([a-zA-Z0-9$_]|(\\[^ \t\b\f\r\n]))* {
91       return lookup_keyword(yytext);
92 }
93 
94 \"[^\"]*\" {
95       process_quoted_string();
96       return QSTRING;
97 }
98 
99   /* Scalar constants. */
100 ("1"?"'"[bB])?"0" { return K_LOGICAL_ZERO; }
101 ("1"?"'"[bB])?"1" { return K_LOGICAL_ONE; }
102 
103   /* Equality operators. */
104 
105 "=="  { return K_EQ; }
106 "!="  { return K_NE; }
107 "==="  { return K_CEQ; }
108 "!=="  { return K_CNE; }
109 
110   /* Other operators. */
111 
112 "&&"  { return K_LAND; }
113 "||"  { return K_LOR; }
114 
115   /* The HCHAR (hierarchy separator) is set by the SDF file itself. We
116      recognize here the HCHAR. */
117 [./] {
118       if (sdf_use_hchar==yytext[0])
119 	    return HCHAR;
120       else
121 	    return yytext[0];
122 }
123 
124 . { return yytext[0]; }
125 
126 %%
127 
128 static struct {
129       const char*name;
130       int code;
131 } keywords[] = {
132       { "ABSOLUTE",     K_ABSOLUTE },
133       { "CELL",         K_CELL },
134       { "CELLTYPE",     K_CELLTYPE },
135       { "DATE",         K_DATE },
136       { "COND",         K_COND },
137       { "CONDELSE",     K_CONDELSE },
138       { "DELAY",        K_DELAY },
139       { "DELAYFILE",    K_DELAYFILE },
140       { "DESIGN",       K_DESIGN },
141       { "DIVIDER",      K_DIVIDER },
142       { "HOLD",         K_HOLD },
143       { "INCREMENT",    K_INCREMENT },
144       { "INTERCONNECT", K_INTERCONNECT },
145       { "INSTANCE",     K_INSTANCE },
146       { "IOPATH",       K_IOPATH },
147       { "PATHPULSE",    K_PATHPULSE },
148       { "PATHPULSEPERCENT", K_PATHPULSEPERCENT },
149       { "PERIOD",       K_PERIOD },
150       { "PROCESS",      K_PROCESS },
151       { "PROGRAM",      K_PROGRAM },
152       { "RECREM",       K_RECREM },
153       { "RECOVERY",     K_RECOVERY },
154       { "REMOVAL",      K_REMOVAL },
155       { "SDFVERSION",   K_SDFVERSION },
156       { "SETUP",        K_SETUP },
157       { "SETUPHOLD",    K_SETUPHOLD },
158       { "TEMPERATURE",  K_TEMPERATURE },
159       { "TIMESCALE",    K_TIMESCALE },
160       { "TIMINGCHECK",  K_TIMINGCHECK },
161       { "VENDOR",       K_VENDOR },
162       { "VERSION",      K_VERSION },
163       { "VOLTAGE",      K_VOLTAGE },
164       { "WIDTH",        K_WIDTH },
165       { 0, IDENTIFIER }
166 };
167 
start_edge_id(unsigned cond)168 void start_edge_id(unsigned cond)
169 {
170       if (cond) BEGIN(COND_EDGE_ID);
171       else BEGIN(EDGE_ID);
172 }
173 
stop_edge_id(void)174 void stop_edge_id(void)
175 {
176       BEGIN(0);
177 }
178 
lookup_keyword(const char * text)179 static int lookup_keyword(const char*text)
180 {
181       unsigned idx, len, skip;
182       for (idx = 0 ;  keywords[idx].name ;  idx += 1) {
183 	    if (strcasecmp(text, keywords[idx].name) == 0)
184 		  return keywords[idx].code;
185       }
186 
187 	/* Process any escaped characters. */
188       skip = 0;
189       len = strlen(yytext);
190       for (idx = 0; idx < len; idx += 1) {
191 	    if (yytext[idx] == '\\') {
192 		  skip += 1;
193 		  idx += 1;
194 	    }
195 	    yytext[idx-skip] = yytext[idx];
196       }
197       yytext[idx-skip] = 0;
198 
199       yylval.string_val = strdup(yytext);
200       return IDENTIFIER;
201 }
202 
203 /*
204  * Create a string without the leading and trailing quotes.
205  */
process_quoted_string(void)206 static void process_quoted_string(void)
207 {
208       char*endp;
209 
210       yylval.string_val = strdup(yytext+1);
211       endp = yylval.string_val+strlen(yylval.string_val);
212       assert(endp[-1] == '"');
213       endp[-1] = 0;
214 }
215 
216 /*
217  * Modern version of flex (>=2.5.9) can clean up the scanner data.
218  */
destroy_sdf_lexor(void)219 static void destroy_sdf_lexor(void)
220 {
221 # ifdef FLEX_SCANNER
222 #   if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5
223 #     if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9
224     yylex_destroy();
225 #     endif
226 #   endif
227 # endif
228 }
229 
230 extern int sdfparse(void);
sdf_process_file(FILE * fd,const char * path)231 void sdf_process_file(FILE*fd, const char*path)
232 {
233       yyrestart(fd);
234 
235       sdf_parse_path = path;
236       sdfparse();
237       destroy_sdf_lexor();
238       sdf_parse_path = 0;
239 }
240