From adf4a90340921cf7a120ae918af776355cf8ca0f Mon Sep 17 00:00:00 2001 From: Artur Kink Date: Mon, 21 Nov 2016 21:08:01 -0500 Subject: Add sql syntax highlighting to code blocks --- src/CMakeLists.txt | 2 + src/context.cpp | 1 + src/docsets.cpp | 1 + src/doxygen.cpp | 2 + src/sqlcode.h | 37 +++++ src/sqlcode.l | 434 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sqlscanner.h | 65 ++++++++ src/types.h | 3 +- src/util.cpp | 5 +- 9 files changed, 548 insertions(+), 2 deletions(-) create mode 100644 src/sqlcode.h create mode 100644 src/sqlcode.l create mode 100644 src/sqlscanner.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d6d217..08c8439 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,7 @@ FLEX_TARGET(commentcnv commentcnv.l ${GENERATED_SRC}/commentcnv.cpp FLEX_TARGET(commentscan commentscan.l ${GENERATED_SRC}/commentscan.cpp COMPILE_FLAGS "${LEX_FLAGS}") FLEX_TARGET(constexp constexp.l ${GENERATED_SRC}/constexp.cpp COMPILE_FLAGS "${LEX_FLAGS}") FLEX_TARGET(xmlcode xmlcode.l ${GENERATED_SRC}/xmlcode.cpp COMPILE_FLAGS "${LEX_FLAGS}") +FLEX_TARGET(sqlcode sqlcode.l ${GENERATED_SRC}/sqlcode.cpp COMPILE_FLAGS "${LEX_FLAGS}") FLEX_TARGET(configimpl configimpl.l ${GENERATED_SRC}/configimpl.cpp COMPILE_FLAGS "${LEX_FLAGS}") BISON_TARGET(constexp constexp.y ${GENERATED_SRC}/ce_parse.cpp COMPILE_FLAGS "${YACC_FLAGS}") @@ -156,6 +157,7 @@ add_library(_doxygen STATIC ${GENERATED_SRC}/commentscan.cpp ${GENERATED_SRC}/constexp.cpp ${GENERATED_SRC}/xmlcode.cpp + ${GENERATED_SRC}/sqlcode.cpp # ${GENERATED_SRC}/ce_parse.cpp # diff --git a/src/context.cpp b/src/context.cpp index 2d4200e..40c3b95 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -1522,6 +1522,7 @@ class DefinitionContext case SrcLangExt_Fortran: result="fortran"; break; case SrcLangExt_VHDL: result="vhdl"; break; case SrcLangExt_XML: result="xml"; break; + case SrcLangExt_SQL: result="sql"; break; case SrcLangExt_Tcl: result="tcl"; break; case SrcLangExt_Markdown: result="markdown"; break; } diff --git a/src/docsets.cpp b/src/docsets.cpp index 4bdb2c9..29b7616 100644 --- a/src/docsets.cpp +++ b/src/docsets.cpp @@ -331,6 +331,7 @@ void DocSets::addIndexItem(Definition *context,MemberDef *md, case SrcLangExt_Fortran: lang="fortran"; break; // Fortran case SrcLangExt_VHDL: lang="vhdl"; break; // VHDL case SrcLangExt_XML: lang="xml"; break; // DBUS XML + case SrcLangExt_SQL: lang="sql"; break; // Sql case SrcLangExt_Tcl: lang="tcl"; break; // Tcl case SrcLangExt_Markdown:lang="markdown"; break; // Markdown case SrcLangExt_Unknown: lang="unknown"; break; // should not happen! diff --git a/src/doxygen.cpp b/src/doxygen.cpp index 4b88a02..d3554cf 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -72,6 +72,7 @@ #include "pyscanner.h" #include "fortranscanner.h" #include "xmlscanner.h" +#include "sqlscanner.h" #include "tclscanner.h" #include "code.h" #include "objcache.h" @@ -10002,6 +10003,7 @@ void initDoxygen() Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed); Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner); Doxygen::parserManager->registerParser("xml", new XMLScanner); + Doxygen::parserManager->registerParser("sql", new SQLScanner); Doxygen::parserManager->registerParser("tcl", new TclLanguageScanner); Doxygen::parserManager->registerParser("md", new MarkdownFileParser); diff --git a/src/sqlcode.h b/src/sqlcode.h new file mode 100644 index 0000000..9c1f7e0 --- /dev/null +++ b/src/sqlcode.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2014 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + + +#ifndef SQLCODE_H +#define SQLCODE_H + +#include "types.h" + +class CodeOutputInterface; +class FileDef; +class MemberDef; +class QCString; +class Definition; + +extern void parseSqlCode(CodeOutputInterface &,const char *,const QCString &, + bool ,const char *,FileDef *fd, + int startLine,int endLine,bool inlineFragment, + MemberDef *memberDef,bool showLineNumbers,Definition *searchCtx, + bool collectXRefs); +extern void resetSqlCodeParserState(); + +#endif diff --git a/src/sqlcode.l b/src/sqlcode.l new file mode 100644 index 0000000..06f9145 --- /dev/null +++ b/src/sqlcode.l @@ -0,0 +1,434 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2014 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +%option never-interactive +%option prefix="sqlcodeYY" + +%{ + +#include + +#include "sqlcode.h" + +#include "entry.h" +#include "doxygen.h" +#include "outputlist.h" +#include "util.h" +#include "membername.h" +#include "searchindex.h" +#include "config.h" +#include "filedef.h" +#include "tooltip.h" + +#define YY_NEVER_INTERACTIVE 1 +#define YY_NO_INPUT 1 +#define YY_NO_UNISTD_H 1 + +static CodeOutputInterface * g_code; +static QCString g_curClassName; +static QCString g_parmType; +static QCString g_parmName; +static const char * g_inputString; //!< the code fragment as text +static int g_inputPosition; //!< read offset during parsing +static int g_inputLines; //!< number of line in the code fragment +static int g_yyLineNr; //!< current line number +static bool g_needsTermination; +static Definition *g_searchCtx; + +static bool g_exampleBlock; +static QCString g_exampleName; +static QCString g_exampleFile; + +static QCString g_type; +static QCString g_name; +static QCString g_args; +static QCString g_classScope; + +static QCString g_CurrScope; + +static FileDef * g_sourceFileDef; +static Definition * g_currentDefinition; +static MemberDef * g_currentMemberDef; +static bool g_includeCodeFragment; +static const char * g_currentFontClass; + +static void codify(const char* text) +{ + g_code->codify(text); +} + +static void setCurrentDoc(const QCString &anchor) +{ + if (Doxygen::searchIndex) + { + if (g_searchCtx) + { + Doxygen::searchIndex->setCurrentDoc(g_searchCtx,g_searchCtx->anchor(),FALSE); + } + else + { + Doxygen::searchIndex->setCurrentDoc(g_sourceFileDef,anchor,TRUE); + } + } +} + +/*! start a new line of code, inserting a line number if g_sourceFileDef + * is TRUE. If a definition starts at the current line, then the line + * number is linked to the documentation of that definition. + */ +static void startCodeLine() +{ + if (g_sourceFileDef) + { + Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr); + + if (!g_includeCodeFragment && d && d->isLinkableInProject()) + { + g_currentDefinition = d; + g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr); + g_classScope = d->name().copy(); + QCString lineAnchor; + lineAnchor.sprintf("l%05d",g_yyLineNr); + if (g_currentMemberDef) + { + g_code->writeLineNumber(g_currentMemberDef->getReference(), + g_currentMemberDef->getOutputFileBase(), + g_currentMemberDef->anchor(),g_yyLineNr); + setCurrentDoc(lineAnchor); + } + else + { + g_code->writeLineNumber(d->getReference(), + d->getOutputFileBase(), + 0,g_yyLineNr); + setCurrentDoc(lineAnchor); + } + } + else + { + g_code->writeLineNumber(0,0,0,g_yyLineNr); + } + } + + g_code->startCodeLine(g_sourceFileDef); + + if (g_currentFontClass) + { + g_code->startFontClass(g_currentFontClass); + } +} + +static void endFontClass() +{ + if (g_currentFontClass) + { + g_code->endFontClass(); + g_currentFontClass=0; + } +} + +static void endCodeLine() +{ + endFontClass(); + g_code->endCodeLine(); +} + +static void nextCodeLine() +{ + const char *fc = g_currentFontClass; + endCodeLine(); + if (g_yyLineNrcodify(sp); + nextCodeLine(); + } + else + { + g_code->codify(sp); + done=TRUE; + } + } +} + +static void startFontClass(const char *s) +{ + endFontClass(); + g_code->startFontClass(s); + g_currentFontClass=s; +} + +/*! counts the number of lines in the input */ +static int countLines() +{ + const char *p=g_inputString; + char c; + int count=1; + while ((c=*p)) + { + p++ ; + if (c=='\n') count++; + } + if (p>g_inputString && *(p-1)!='\n') + { // last line does not end with a \n, so we add an extra + // line and explicitly terminate the line after parsing. + count++, + g_needsTermination=TRUE; + } + return count; +} + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + while( c < max_size && g_inputString[g_inputPosition] ) + { + *buf = g_inputString[g_inputPosition++] ; + c++; buf++; + } + return c; +} + +%} + +nl (\r\n|\r|\n) +ws [ \t]+ +idchar [A-Za-z0-9\-_]+ +keywords1 ("ADD"|"ALL"|"ALLOCATE"|"ALTER"|"AND"|"ANY"|"ARE"|"AS"|"ASENSITIVE"|"ASYMMETRIC"|"AT"|"ATOMIC"|"AUTHORIZATION"|"BETWEEN"|"BOTH"|"BY"|"CALL"|"CALLED"|"CASCADED"|"CAST") +keywords2 ("CHECK"|"CLOSE"|"COLLATE"|"COLUMN"|"COMMIT"|"CONNECT"|"CONSTRAINT"|"CONTINUE"|"CORRESPONDING"|"CREATE"|"CROSS"|"CUBE"|"CURRENT"|"CURRENT_DATE"|"CURRENT_DEFAULT_TRANSFORM_GROUP") +keywords3 ("CURRENT_PATH"|"CURRENT_ROLE"|"CURRENT_TIME"|"CURRENT_TIMESTAMP"|"CURRENT_TRANSFORM_GROUP_FOR_TYPE"|"CURRENT_USER") +keywords4 ("CURSOR"|"CYCLE"|"DAY"|"DEALLOCATE"|"DECLARE"|"DEFAULT"|"DELETE"|"DEREF"|"DESCRIBE"|"DETERMINISTIC"|"DISCONNECT"|"DISTINCT"|"DROP"|"DYNAMIC") +keywords5 ("EACH"|"ELEMENT"|"END-EXEC"|"ESCAPE"|"EXCEPT"|"EXEC"|"EXECUTE"|"EXISTS"|"EXTERNAL"|"FETCH"|"FILTER"|"FOR"|"FOREIGN"|"FREE"|"FROM"|"FULL"|"FUNCTION") +keywords6 ("GET"|"GLOBAL"|"GRANT"|"GROUP"|"GROUPING"|"HAVING"|"HOLD"|"HOUR"|"IDENTITY"|"IMMEDIATE"|"IN"|"INDICATOR"|"INNER"|"INOUT"|"INPUT"|"INSENSITIVE"|"INSERT"|"INTERSECT") +keywords7 ("INTERVAL"|"INTO"|"IS"|"ISOLATION"|"JOIN"|"LANGUAGE"|"LARGE"|"LATERAL"|"LEADING"|"LEFT"|"LIKE"|"LOCAL"|"LOCALTIME"|"LOCALTIMESTAMP"|"MATCH"|"MEMBER"|"MERGE"|"METHOD"|"MINUTE") +keywords8 ("MODIFIES"|"MODULE"|"MONTH"|"MULTISET"|"NATIONAL"|"NATURAL"|"NEW"|"NO"|"NONE"|"NOT"|"OF"|"OLD"|"ON"|"ONLY"|"OPEN"|"OR"|"ORDER"|"OUT"|"OUTER"|"OUTPUT") +keywords9 ("OVER"|"OVERLAPS"|"PARAMETER"|"PARTITION"|"PRECISION"|"PREPARE"|"PRIMARY"|"PROCEDURE"|"RANGE"|"READS"|"RECURSIVE"|"REF"|"REFERENCES"|"REFERENCING"|"REGR_AVGX"|"REGR_AVGY") +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") +keywords11 ("SCROLL"|"SEARCH"|"SECOND"|"SELECT"|"SENSITIVE"|"SESSION_USER"|"SET"|"SIMILAR"|"SOME"|"SPECIFIC"|"SPECIFICTYPE"|"SQL"|"SQLEXCEPTION"|"SQLSTATE"|"SQLWARNING"|"START"|"STATIC") +keywords12 ("SUBMULTISET"|"SYMMETRIC"|"SYSTEM"|"SYSTEM_USER"|"TABLE"|"THEN"|"TIMEZONE_HOUR"|"TIMEZONE_MINUTE"|"TO"|"TRAILING"|"TRANSLATION"|"TREAT"|"TRIGGER"|"UESCAPE"|"UNION") +keywords13 ("UNIQUE"|"UNNEST"|"UPDATE"|"UPPER"|"USER"|"USING"|"VALUE"|"VALUES"|"VAR_POP"|"VAR_SAMP"|"VARYING"|"WHEN"|"WHENEVER"|"WHERE"|"WIDTH_BUCKET"|"WINDOW"|"WITH"|"WITHIN"|"WITHOUT"|"YEAR") + +/* Need multiple keyword definitions due to max length */ +keyword (?i:{keywords1}|{keywords2}|{keywords3}|{keywords4}|{keywords5}|{keywords6}|{keywords7}|{keywords8}|{keywords9}|{keywords10}|{keywords11}|{keywords12}|{keywords13}) + +typekeyword (?i:"ARRAY"|"BIGINT"|"BINARY"|"BLOB"|"BOOLEAN"|"CHAR"|"CHARACTER"|"CLOB"|"DATE"|"DEC"|"DECIMAL"|"DOUBLE"|"FLOAT"|"INT"|"INTEGER"|"NCHAR"|"NCLOB"|"NUMERIC"|"REAL"|"SMALLINT"|"TIME"|"TIMESTAMP"|"VARCHAR") + +flowkeyword (?i:"CASE"|"IF"|"ELSE"|"BEGIN"|"END"|"WHILE") + +literalkeyword (?i:"FALSE"|"TRUE"|"NULL"|"UNKNOWN") +stringliteral (\"[^"]*\")|('[^']*') +number [0-9]+ +literals ({literalkeyword}|{stringliteral}|{number}) + +variable @{idchar}+ + +simplecomment --.* +commentopen "/\*" +commentclose "\*/" + +%option noyywrap +%option nounput + +%x COMMENT + +%% + +{literals} { + startFontClass("stringliteral"); + codifyLines(yytext); + endFontClass(); + } + + +{keyword} { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } + +{flowkeyword} { + startFontClass("keywordflow"); + codifyLines(yytext); + endFontClass(); + } + +{typekeyword} { + startFontClass("keywordtype"); + codifyLines(yytext); + endFontClass(); + } + +{variable} { + startFontClass("preprocessor"); + codifyLines(yytext); + endFontClass(); + } + +{simplecomment} { + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } + +{commentopen} { + startFontClass("comment"); + codifyLines(yytext); + BEGIN(COMMENT); + } + +. { + codifyLines(yytext); + } +{nl} { + codifyLines(yytext); + } + +{commentclose} { + codifyLines(yytext); + endFontClass(); + BEGIN(INITIAL); + } + +{idchar} { + codifyLines(yytext); + } + +{nl} { + codifyLines(yytext); + } + +. { + codifyLines(yytext); + } + +%% + +void parseSqlCode( + CodeOutputInterface &od, + const char * /*className*/, + const QCString &s, + bool exBlock, + const char *exName, + FileDef *fd, + int startLine, + int endLine, + bool inlineFragment, + MemberDef *, + bool,Definition *searchCtx, + bool /*collectXRefs*/ + ) +{ + if (s.isEmpty()) return; + + TooltipManager::instance()->clearTooltips(); + + g_code = &od; + g_inputString = s; + g_inputPosition = 0; + g_currentFontClass = 0; + g_needsTermination = FALSE; + g_searchCtx=searchCtx; + + if (startLine!=-1) + g_yyLineNr = startLine; + else + g_yyLineNr = 1; + + if (endLine!=-1) + g_inputLines = endLine+1; + else + g_inputLines = g_yyLineNr + countLines() - 1; + + g_exampleBlock = exBlock; + g_exampleName = exName; + g_sourceFileDef = fd; + + bool cleanupSourceDef = FALSE; + + if (exBlock && fd==0) + { + // create a dummy filedef for the example + g_sourceFileDef = new FileDef("",(exName?exName:"generated")); + cleanupSourceDef = TRUE; + } + + if (g_sourceFileDef) + { + setCurrentDoc("l00001"); + } + + g_includeCodeFragment = inlineFragment; + // Starts line 1 on the output + startCodeLine(); + + sqlcodeYYrestart( sqlcodeYYin ); + + sqlcodeYYlex(); + + if (g_needsTermination) + { + endCodeLine(); + } + if (fd) + { + TooltipManager::instance()->writeTooltips(*g_code); + } + if (cleanupSourceDef) + { + // delete the temporary file definition used for this example + delete g_sourceFileDef; + g_sourceFileDef=0; + } + + return; +} + +void resetSqlCodeParserState() +{ + g_currentDefinition = 0; + g_currentMemberDef = 0; +} + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +extern "C" { // some bogus code to keep the compiler happy + void sqlcodeYYdummy() { yy_flex_realloc(0,0); } +} +#elif YY_FLEX_MAJOR_VERSION<=2 && YY_FLEX_MINOR_VERSION<=5 && YY_FLEX_SUBMINOR_VERSION<33 +#error "You seem to be using a version of flex newer than 2.5.4. These are currently incompatible with 2.5.4, and do NOT work with doxygen! Please use version 2.5.4 or expect things to be parsed wrongly! A bug report has been submitted (#732132)." +#endif + diff --git a/src/sqlscanner.h b/src/sqlscanner.h new file mode 100644 index 0000000..7afa869 --- /dev/null +++ b/src/sqlscanner.h @@ -0,0 +1,65 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2015 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#ifndef SQLSCANNER_H +#define SQLSCANNER_H + +#include "parserintf.h" +#include "sqlcode.h" + +/** SQL scanner. Only support syntax highlighting of code at the moment. + */ +class SQLScanner : public ParserInterface +{ +public: + SQLScanner() {} + virtual ~SQLScanner() {} + void startTranslationUnit(const char *) {} + void finishTranslationUnit() {} + void parseInput(const char *, const char *, Entry *, bool , QStrList &) {} + bool needsPreprocessing(const QCString &) { return FALSE; } + + void parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + SrcLangExt, + bool isExampleBlock, + const char *exampleName=0, + FileDef *fileDef=0, + int startLine=-1, + int endLine=-1, + bool inlineFragment=FALSE, + MemberDef *memberDef=0, + bool showLineNumbers=TRUE, + Definition *searchCtx=0, + bool collectXRefs=TRUE + ) + { + parseSqlCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, + fileDef,startLine,endLine,inlineFragment,memberDef, + showLineNumbers,searchCtx,collectXRefs); + } + + void resetCodeParserState() + { + resetSqlCodeParserState(); + } + + void parsePrototype(const char *) {} + +private: +}; + +#endif diff --git a/src/types.h b/src/types.h index f6c704c..806e6fc 100644 --- a/src/types.h +++ b/src/types.h @@ -54,7 +54,8 @@ enum SrcLangExt SrcLangExt_VHDL = 0x02000, SrcLangExt_XML = 0x04000, SrcLangExt_Tcl = 0x08000, - SrcLangExt_Markdown = 0x10000 + SrcLangExt_Markdown = 0x10000, + SrcLangExt_SQL = 0x20000 }; /** Grouping info */ diff --git a/src/util.cpp b/src/util.cpp index 44f635e..94c6bd7 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -329,7 +329,8 @@ int guessSection(const char *name) n.right(4)==".ipp" || n.right(4)==".i++" || n.right(4)==".inl" || - n.right(4)==".xml" + n.right(4)==".xml" || + n.right(4)==".sql" ) return Entry::SOURCE_SEC; if (n.right(2)==".h" || // header n.right(3)==".hh" || @@ -7061,6 +7062,7 @@ g_lang2extMap[] = { "fortranfixed", "fortranfixed", SrcLangExt_Fortran }, { "vhdl", "vhdl", SrcLangExt_VHDL }, { "xml", "xml", SrcLangExt_XML }, + { "sql", "sql", SrcLangExt_SQL }, { "tcl", "tcl", SrcLangExt_Tcl }, { "md", "md", SrcLangExt_Markdown }, { 0, 0, (SrcLangExt)0 } @@ -7164,6 +7166,7 @@ void initDefaultExtensionMapping() void addCodeOnlyMappings() { updateLanguageMapping(".xml", "xml"); + updateLanguageMapping(".sql", "sql"); } SrcLangExt getLanguageFromFileName(const QCString fileName) -- cgit v0.12