Doxygen
sqlcode.l
浏览该文件的文档.
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2020 by Dimitri van Heesch.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation under the terms of the GNU General Public License is hereby
7  * granted. No representations are made about the suitability of this software
8  * for any purpose. It is provided "as is" without express or implied warranty.
9  * See the GNU General Public License for more details.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15 
16 %option never-interactive
17 %option prefix="sqlcodeYY"
18 %option noyywrap
19 %option nounput
20 %option reentrant
21 %option extra-type="struct sqlcodeYY_state *"
22 %top{
23 #include <stdint.h>
24 // forward declare yyscan_t to improve type safety
25 #define YY_TYPEDEF_YY_SCANNER_T
26 struct yyguts_t;
27 typedef yyguts_t *yyscan_t;
28 }
29 
30 %{
31 
32 #include <stdio.h>
33 
34 #include "sqlcode.h"
35 
36 #include "entry.h"
37 #include "doxygen.h"
38 #include "outputlist.h"
39 #include "util.h"
40 #include "membername.h"
41 #include "searchindex.h"
42 #include "config.h"
43 #include "filedef.h"
44 #include "tooltip.h"
45 #include "message.h"
46 
47 #define YY_NEVER_INTERACTIVE 1
48 #define YY_NO_INPUT 1
49 #define YY_NO_UNISTD_H 1
50 
51 #define USE_STATE2STRING 0
52 
53 struct sqlcodeYY_state
54 {
55  CodeOutputInterface * code;
56  const char *inputString; //!< the code fragment as text
57  yy_size_t inputPosition; //!< read offset during parsing
58  int inputLines; //!< number of line in the code fragment
59  int yyLineNr; //!< current line number
60  bool needsTermination;
61  const Definition *searchCtx;
62 
63  bool exampleBlock;
64  QCString exampleName;
65  QCString classScope;
66 
67  const FileDef *sourceFileDef;
68  const Definition *currentDefinition;
69  const MemberDef *currentMemberDef;
70  bool includeCodeFragment;
71  const char *currentFontClass;
72 };
73 
74 #if USE_STATE2STRING
75 static const char *stateToString(int state);
76 #endif
77 
78 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
79 static void startCodeLine(yyscan_t yyscanner);
80 static void endFontClass(yyscan_t yyscanner);
81 static void endCodeLine(yyscan_t yyscanner);
82 static void nextCodeLine(yyscan_t yyscanner);
83 static void codifyLines(yyscan_t yyscanner,const char *text);
84 static void startFontClass(yyscan_t yyscanner,const char *s);
85 static int countLines(yyscan_t yyscanner);
86 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
87 
88 #undef YY_INPUT
89 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
90 
91 %}
92 
93 nl (\r\n|\r|\n)
94 ws [ \t]+
95 idchar [A-Za-z0-9\-_]+
96 keywords1 ("ADD"|"ALL"|"ALLOCATE"|"ALTER"|"AND"|"ANY"|"ARE"|"AS"|"ASENSITIVE"|"ASYMMETRIC"|"AT"|"ATOMIC"|"AUTHORIZATION"|"BETWEEN"|"BOTH"|"BY"|"CALL"|"CALLED"|"CASCADED"|"CAST")
97 keywords2 ("CHECK"|"CLOSE"|"COLLATE"|"COLUMN"|"COMMIT"|"CONNECT"|"CONSTRAINT"|"CONTINUE"|"CORRESPONDING"|"CREATE"|"CROSS"|"CUBE"|"CURRENT"|"CURRENT_DATE"|"CURRENT_DEFAULT_TRANSFORM_GROUP")
98 keywords3 ("CURRENT_PATH"|"CURRENT_ROLE"|"CURRENT_TIME"|"CURRENT_TIMESTAMP"|"CURRENT_TRANSFORM_GROUP_FOR_TYPE"|"CURRENT_USER")
99 keywords4 ("CURSOR"|"CYCLE"|"DAY"|"DEALLOCATE"|"DECLARE"|"DEFAULT"|"DELETE"|"DEREF"|"DESCRIBE"|"DETERMINISTIC"|"DISCONNECT"|"DISTINCT"|"DROP"|"DYNAMIC")
100 keywords5 ("EACH"|"ELEMENT"|"END-EXEC"|"ESCAPE"|"EXCEPT"|"EXEC"|"EXECUTE"|"EXISTS"|"EXTERNAL"|"FETCH"|"FILTER"|"FOR"|"FOREIGN"|"FREE"|"FROM"|"FULL"|"FUNCTION")
101 keywords6 ("GET"|"GLOBAL"|"GRANT"|"GROUP"|"GROUPING"|"HAVING"|"HOLD"|"HOUR"|"IDENTITY"|"IMMEDIATE"|"IN"|"INDICATOR"|"INNER"|"INOUT"|"INPUT"|"INSENSITIVE"|"INSERT"|"INTERSECT")
102 keywords7 ("INTERVAL"|"INTO"|"IS"|"ISOLATION"|"JOIN"|"LANGUAGE"|"LARGE"|"LATERAL"|"LEADING"|"LEFT"|"LIKE"|"LOCAL"|"LOCALTIME"|"LOCALTIMESTAMP"|"MATCH"|"MEMBER"|"MERGE"|"METHOD"|"MINUTE")
103 keywords8 ("MODIFIES"|"MODULE"|"MONTH"|"MULTISET"|"NATIONAL"|"NATURAL"|"NEW"|"NO"|"NONE"|"NOT"|"OF"|"OLD"|"ON"|"ONLY"|"OPEN"|"OR"|"ORDER"|"OUT"|"OUTER"|"OUTPUT")
104 keywords9 ("OVER"|"OVERLAPS"|"PARAMETER"|"PARTITION"|"PRECISION"|"PREPARE"|"PRIMARY"|"PROCEDURE"|"RANGE"|"READS"|"RECURSIVE"|"REF"|"REFERENCES"|"REFERENCING"|"REGR_AVGX"|"REGR_AVGY")
105 keywords10 ("REGR_COUNT"|"REGR_INTERCEPT"|"REGR_R2"|"REGR_SLOPE"|"REGR_SXX"|"REGR_SXY"|"REGR_SYY"|"RELEASE"|"RESULT"|"RETURN"|"RETURNS"|"REVOKE"|"RIGHT"|"ROLLBACK"|"ROLLUP"|"ROW"|"ROWS"|"SAVEPOINT")
106 keywords11 ("SCROLL"|"SEARCH"|"SECOND"|"SELECT"|"SENSITIVE"|"SESSION_USER"|"SET"|"SIMILAR"|"SOME"|"SPECIFIC"|"SPECIFICTYPE"|"SQL"|"SQLEXCEPTION"|"SQLSTATE"|"SQLWARNING"|"START"|"STATIC")
107 keywords12 ("SUBMULTISET"|"SYMMETRIC"|"SYSTEM"|"SYSTEM_USER"|"TABLE"|"THEN"|"TIMEZONE_HOUR"|"TIMEZONE_MINUTE"|"TO"|"TRAILING"|"TRANSLATION"|"TREAT"|"TRIGGER"|"UESCAPE"|"UNION")
108 keywords13 ("UNIQUE"|"UNNEST"|"UPDATE"|"UPPER"|"USER"|"USING"|"VALUE"|"VALUES"|"VAR_POP"|"VAR_SAMP"|"VARYING"|"WHEN"|"WHENEVER"|"WHERE"|"WIDTH_BUCKET"|"WINDOW"|"WITH"|"WITHIN"|"WITHOUT"|"YEAR")
109 
110 /* Need multiple keyword definitions due to max length */
111 keyword (?i:{keywords1}|{keywords2}|{keywords3}|{keywords4}|{keywords5}|{keywords6}|{keywords7}|{keywords8}|{keywords9}|{keywords10}|{keywords11}|{keywords12}|{keywords13})
112 
113 typekeyword (?i:"ARRAY"|"BIGINT"|"BINARY"|"BLOB"|"BOOLEAN"|"CHAR"|"CHARACTER"|"CLOB"|"DATE"|"DEC"|"DECIMAL"|"DOUBLE"|"FLOAT"|"INT"|"INTEGER"|"NCHAR"|"NCLOB"|"NUMERIC"|"NVARCHAR"|"REAL"|"SMALLINT"|"TIME"|"TIMESTAMP"|"VARCHAR")
114 
115 flowkeyword (?i:"CASE"|"IF"|"ELSE"|"BEGIN"|"END"|"WHILE")
116 
117 literalkeyword (?i:"false"|"true"|"NULL"|"UNKNOWN")
118 stringliteral (\"[^"]*\")|('[^']*')
119 number [0-9]+
120 literals ({literalkeyword}|{stringliteral}|{number})
121 
122 variable @{idchar}+
123 
124 simplecomment --.*
125 commentopen "/\*"
126 commentclose "\*\/"
127 
128 %x COMMENT
129 
130 %%
131 
132 {literals} {
133  startFontClass(yyscanner,"stringliteral");
134  codifyLines(yyscanner,yytext);
135  endFontClass(yyscanner);
136  }
137 
138 
139 {keyword} {
140  startFontClass(yyscanner,"keyword");
141  codifyLines(yyscanner,yytext);
142  endFontClass(yyscanner);
143  }
144 
145 {flowkeyword} {
146  startFontClass(yyscanner,"keywordflow");
147  codifyLines(yyscanner,yytext);
148  endFontClass(yyscanner);
149  }
150 
151 {typekeyword} {
152  startFontClass(yyscanner,"keywordtype");
153  codifyLines(yyscanner,yytext);
154  endFontClass(yyscanner);
155  }
156 
157 {variable} {
158  startFontClass(yyscanner,"preprocessor");
159  codifyLines(yyscanner,yytext);
160  endFontClass(yyscanner);
161  }
162 
163 {simplecomment} {
164  startFontClass(yyscanner,"comment");
165  codifyLines(yyscanner,yytext);
166  endFontClass(yyscanner);
167  }
168 
169 {commentopen} {
170  startFontClass(yyscanner,"comment");
171  codifyLines(yyscanner,yytext);
172  BEGIN(COMMENT);
173  }
174 
175 <COMMENT>. {
176  codifyLines(yyscanner,yytext);
177 
178  }
179 <COMMENT>{nl} {
180  codifyLines(yyscanner,yytext);
181  }
182 
183 <COMMENT>{commentclose} {
184  codifyLines(yyscanner,yytext);
185  endFontClass(yyscanner);
186  BEGIN(INITIAL);
187  }
188 
189 {idchar} {
190  codifyLines(yyscanner,yytext);
191  }
192 
193 {nl} {
194  codifyLines(yyscanner,yytext);
195  }
196 
197 [\x80-\xFF]* { // keep utf8 characters together...
198  codifyLines(yyscanner,yytext);
199  }
200 . {
201  codifyLines(yyscanner,yytext);
202  }
203 
204 %%
205 
206 
207 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
208 {
209  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
210  if (Doxygen::searchIndex)
211  {
212  if (yyextra->searchCtx)
213  {
214  yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),false);
215  }
216  else
217  {
218  yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,true);
219  }
220  }
221 }
222 
223 /*! start a new line of code, inserting a line number if yyextra->sourceFileDef
224  * is true. If a definition starts at the current line, then the line
225  * number is linked to the documentation of that definition.
226  */
227 static void startCodeLine(yyscan_t yyscanner)
228 {
229  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
230  if (yyextra->sourceFileDef)
231  {
232  const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
233 
234  if (!yyextra->includeCodeFragment && d && d->isLinkableInProject())
235  {
236  yyextra->currentDefinition = d;
237  yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
238  yyextra->classScope = d->name();
239  QCString lineAnchor;
240  lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
241  if (yyextra->currentMemberDef)
242  {
243  yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
244  yyextra->currentMemberDef->getOutputFileBase(),
245  yyextra->currentMemberDef->anchor(),yyextra->yyLineNr,
246  !yyextra->includeCodeFragment);
247  setCurrentDoc(yyscanner,lineAnchor);
248  }
249  else
250  {
251  yyextra->code->writeLineNumber(d->getReference(),
252  d->getOutputFileBase(),
253  QCString(),yyextra->yyLineNr,
254  !yyextra->includeCodeFragment);
255  setCurrentDoc(yyscanner,lineAnchor);
256  }
257  }
258  else
259  {
260  yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
261  !yyextra->includeCodeFragment);
262  }
263  }
264 
265  yyextra->code->startCodeLine(yyextra->sourceFileDef);
266 
267  if (yyextra->currentFontClass)
268  {
269  yyextra->code->startFontClass(yyextra->currentFontClass);
270  }
271 }
272 
273 static void endFontClass(yyscan_t yyscanner)
274 {
275  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
276  if (yyextra->currentFontClass)
277  {
278  yyextra->code->endFontClass();
279  yyextra->currentFontClass=0;
280  }
281 }
282 
283 static void endCodeLine(yyscan_t yyscanner)
284 {
285  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
286  endFontClass(yyscanner);
287  yyextra->code->endCodeLine();
288 }
289 
290 static void nextCodeLine(yyscan_t yyscanner)
291 {
292  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
293  const char *fc = yyextra->currentFontClass;
294  endCodeLine(yyscanner);
295  if (yyextra->yyLineNr<yyextra->inputLines)
296  {
297  yyextra->currentFontClass = fc;
298  startCodeLine(yyscanner);
299  }
300 }
301 
302 static void codifyLines(yyscan_t yyscanner,const char *text)
303 {
304  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
305  const char *p=text,*sp=p;
306  char c;
307  bool done=false;
308  while (!done)
309  {
310  sp=p;
311  while ((c=*p++) && c!='\n') { }
312  if (c=='\n')
313  {
314  yyextra->yyLineNr++;
315  int l = (int)(p-sp-1);
316  char *tmp = (char*)malloc(l+1);
317  memcpy(tmp,sp,l);
318  tmp[l]='\0';
319  yyextra->code->codify(tmp);
320  free(tmp);
321  nextCodeLine(yyscanner);
322  }
323  else
324  {
325  yyextra->code->codify(sp);
326  done=true;
327  }
328  }
329 }
330 
331 static void startFontClass(yyscan_t yyscanner,const char *s)
332 {
333  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
334  endFontClass(yyscanner);
335  yyextra->code->startFontClass(s);
336  yyextra->currentFontClass=s;
337 }
338 
339 /*! counts the number of lines in the input */
340 static int countLines(yyscan_t yyscanner)
341 {
342  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
343  const char *p=yyextra->inputString;
344  char c;
345  int count=1;
346  while ((c=*p))
347  {
348  p++ ;
349  if (c=='\n') count++;
350  }
351  if (p>yyextra->inputString && *(p-1)!='\n')
352  { // last line does not end with a \n, so we add an extra
353  // line and explicitly terminate the line after parsing.
354  count++,
355  yyextra->needsTermination=true;
356  }
357  return count;
358 }
359 
360 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
361 {
362  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
363  yy_size_t inputPosition = yyextra->inputPosition;
364  const char *s = yyextra->inputString + inputPosition;
365  yy_size_t c=0;
366  while( c < max_size && *s )
367  {
368  *buf++ = *s++;
369  c++;
370  }
371  yyextra->inputPosition += c;
372  return c;
373 }
374 
375 
376 // public interface -----------------------------------------------------------
377 
378 struct SQLCodeParser::Private
379 {
380  yyscan_t yyscanner;
381  sqlcodeYY_state state;
382 };
383 
384 SQLCodeParser::SQLCodeParser() : p(std::make_unique<Private>())
385 {
386  sqlcodeYYlex_init_extra(&p->state, &p->yyscanner);
387 #ifdef FLEX_DEBUG
388  sqlcodeYYset_debug(1,p->yyscanner);
389 #endif
390  resetCodeParserState();
391 }
392 
393 SQLCodeParser::~SQLCodeParser()
394 {
395  sqlcodeYYlex_destroy(p->yyscanner);
396 }
397 
398 void SQLCodeParser::resetCodeParserState()
399 {
400  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
401  yyextra->currentDefinition = 0;
402  yyextra->currentMemberDef = 0;
403 }
404 
405 void SQLCodeParser::parseCode(CodeOutputInterface &codeOutIntf,
406  const QCString &scopeName,
407  const QCString &input,
408  SrcLangExt,
409  bool isExampleBlock,
410  const QCString &exampleName,
411  const FileDef *fileDef,
412  int startLine,
413  int endLine,
414  bool inlineFragment,
415  const MemberDef *memberDef,
416  bool showLineNumbers,
417  const Definition *searchCtx,
418  bool collectXRefs
419  )
420 {
421  yyscan_t yyscanner = p->yyscanner;
422  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
423 
424  if (input.isEmpty()) return;
425 
426  printlex(yy_flex_debug, true, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
427 
428  yyextra->code = &codeOutIntf;
429  yyextra->inputString = input.data();
430  yyextra->inputPosition = 0;
431  yyextra->currentFontClass = 0;
432  yyextra->needsTermination = false;
433  yyextra->searchCtx=searchCtx;
434 
435  if (startLine!=-1)
436  yyextra->yyLineNr = startLine;
437  else
438  yyextra->yyLineNr = 1;
439 
440  if (endLine!=-1)
441  yyextra->inputLines = endLine+1;
442  else
443  yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
444 
445  yyextra->exampleBlock = isExampleBlock;
446  yyextra->exampleName = exampleName;
447  yyextra->sourceFileDef = fileDef;
448 
449  bool cleanupSourceDef = false;
450 
451  if (isExampleBlock && fileDef==0)
452  {
453  // create a dummy filedef for the example
454  yyextra->sourceFileDef = createFileDef(QCString(),!exampleName.isEmpty() ? exampleName : QCString("generated"));
455  cleanupSourceDef = true;
456  }
457 
458  if (yyextra->sourceFileDef)
459  {
460  setCurrentDoc(yyscanner,"l00001");
461  }
462 
463  yyextra->includeCodeFragment = inlineFragment;
464  // Starts line 1 on the output
465  startCodeLine(yyscanner);
466 
467  sqlcodeYYrestart( 0, yyscanner );
468 
469  sqlcodeYYlex(yyscanner);
470 
471  if (yyextra->needsTermination)
472  {
473  endCodeLine(yyscanner);
474  }
475  if (cleanupSourceDef)
476  {
477  // delete the temporary file definition used for this example
478  delete yyextra->sourceFileDef;
479  yyextra->sourceFileDef=0;
480  }
481 
482  printlex(yy_flex_debug, false, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
483 }
484 
485 //---------------------------------------------------------------------------------
486 
487 #if USE_STATE2STRING
488 #include "sqlcode.l.h"
489 #endif