diff options
Diffstat (limited to 'src/LexVHDL.cpp')
-rwxr-xr-x | src/LexVHDL.cpp | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/src/LexVHDL.cpp b/src/LexVHDL.cpp new file mode 100755 index 0000000..0feef95 --- /dev/null +++ b/src/LexVHDL.cpp @@ -0,0 +1,473 @@ +// Scintilla source code edit control +/** @file LexVHDL.cxx + ** Lexer for VHDL + ** Written by Phil Reid, + ** Based on: + ** - The Verilog Lexer by Avi Yegudin + ** - The Fortran Lexer by Chuan-jian Shen + ** - The C++ lexer by Neil Hodgson + **/ +// Copyright 1998-2002 by Neil Hodgson <[email protected]> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <stdarg.h> + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" + +static void ColouriseVHDLDoc( + unsigned int startPos, + int length, + int initStyle, + WordList *keywordlists[], + Accessor &styler); + + +/***************************************/ +static inline bool IsAWordChar(const int ch) { + return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' ); +} + +/***************************************/ +static inline bool IsAWordStart(const int ch) { + return (ch < 0x80) && (isalnum(ch) || ch == '_'); +} + +/***************************************/ +inline bool IsABlank(unsigned int ch) { + return (ch == ' ') || (ch == 0x09) || (ch == 0x0b) ; +} + +/***************************************/ +static void ColouriseVHDLDoc( + unsigned int startPos, + int length, + int initStyle, + WordList *keywordlists[], + Accessor &styler) +{ + WordList &Keywords = *keywordlists[0]; + WordList &Operators = *keywordlists[1]; + WordList &Attributes = *keywordlists[2]; + WordList &Functions = *keywordlists[3]; + WordList &Packages = *keywordlists[4]; + WordList &Types = *keywordlists[5]; + WordList &User = *keywordlists[6]; + + StyleContext sc(startPos, length, initStyle, styler); + + for (; sc.More(); sc.Forward()) + { + + // Determine if the current state should terminate. + if (sc.state == SCE_VHDL_OPERATOR) { + sc.SetState(SCE_VHDL_DEFAULT); + } else if (sc.state == SCE_VHDL_NUMBER) { + if (!IsAWordChar(sc.ch) && (sc.ch != '#')) { + sc.SetState(SCE_VHDL_DEFAULT); + } + } else if (sc.state == SCE_VHDL_IDENTIFIER) { + if (!IsAWordChar(sc.ch) || (sc.ch == '.')) { + char s[100]; + sc.GetCurrentLowered(s, sizeof(s)); + if (Keywords.InList(s)) { + sc.ChangeState(SCE_VHDL_KEYWORD); + } else if (Operators.InList(s)) { + sc.ChangeState(SCE_VHDL_STDOPERATOR); + } else if (Attributes.InList(s)) { + sc.ChangeState(SCE_VHDL_ATTRIBUTE); + } else if (Functions.InList(s)) { + sc.ChangeState(SCE_VHDL_STDFUNCTION); + } else if (Packages.InList(s)) { + sc.ChangeState(SCE_VHDL_STDPACKAGE); + } else if (Types.InList(s)) { + sc.ChangeState(SCE_VHDL_STDTYPE); + } else if (User.InList(s)) { + sc.ChangeState(SCE_VHDL_USERWORD); + } + sc.SetState(SCE_VHDL_DEFAULT); + } + } else if (sc.state == SCE_VHDL_COMMENT || sc.state == SCE_V_COMMENTLINEBANG) { + if (sc.atLineEnd) { + sc.SetState(SCE_VHDL_DEFAULT); + } + } else if (sc.state == SCE_VHDL_STRING) { + if (sc.ch == '\\') { + if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { + sc.Forward(); + } + } else if (sc.ch == '\"') { + sc.ForwardSetState(SCE_VHDL_DEFAULT); + } else if (sc.atLineEnd) { + sc.ChangeState(SCE_V_STRINGEOL); + sc.ForwardSetState(SCE_VHDL_DEFAULT); + } + } + + // Determine if a new state should be entered. + if (sc.state == SCE_VHDL_DEFAULT) { + if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { + sc.SetState(SCE_VHDL_NUMBER); + } else if (IsAWordStart(sc.ch)) { + sc.SetState(SCE_VHDL_IDENTIFIER); + } else if (sc.Match('-', '-')) { + sc.SetState(SCE_VHDL_COMMENT); + sc.Forward(); + } else if (sc.Match('-', '-')) { + if (sc.Match("--!")) // Nice to have a different comment style + sc.SetState(SCE_VHDL_COMMENTLINEBANG); + else + sc.SetState(SCE_VHDL_COMMENT); + } else if (sc.ch == '\"') { + sc.SetState(SCE_VHDL_STRING); + } else if (isoperator(static_cast<char>(sc.ch))) { + sc.SetState(SCE_VHDL_OPERATOR); + } + } + } + sc.Complete(); +} +//============================================================================= +static bool IsCommentLine(int line, Accessor &styler) { + int pos = styler.LineStart(line); + int eol_pos = styler.LineStart(line + 1) - 1; + for (int i = pos; i < eol_pos; i++) { + char ch = styler[i]; + char chNext = styler[i+1]; + if ((ch == '-') && (chNext == '-')) + return true; + else if (ch != ' ' && ch != '\t') + return false; + } + return false; +} + +//============================================================================= +// Folding the code +static void FoldNoBoxVHDLDoc( + unsigned int startPos, + int length, + int initStyle, + Accessor &styler) +{ + // Decided it would be smarter to have the lexer have all keywords included. Therefore I + // don't check if the style for the keywords that I use to adjust the levels. + char words[] = + "architecture begin case component else elsif end entity generate loop package process record then " + "procedure function when"; + WordList keywords; + keywords.Set(words); + + bool foldComment = styler.GetPropertyInt("fold.comment", 1) != 0; + bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; + bool foldAtElse = styler.GetPropertyInt("fold.at.else", 1) != 0; + bool foldAtBegin = styler.GetPropertyInt("fold.at.Begin", 1) != 0; + bool foldAtParenthese = styler.GetPropertyInt("fold.at.Parenthese", 1) != 0; + //bool foldAtWhen = styler.GetPropertyInt("fold.at.When", 1) != 0; //< fold at when in case statements + + int visibleChars = 0; + unsigned int endPos = startPos + length; + + int lineCurrent = styler.GetLine(startPos); + int levelCurrent = SC_FOLDLEVELBASE; + if(lineCurrent > 0) + levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; + //int levelMinCurrent = levelCurrent; + int levelMinCurrentElse = levelCurrent; //< Used for folding at 'else' + int levelMinCurrentBegin = levelCurrent; //< Used for folding at 'begin' + int levelNext = levelCurrent; + + /***************************************/ + int lastStart = 0; + char prevWord[32] = ""; + + /***************************************/ + // Find prev word + // The logic for going up or down a level depends on a the previous keyword + // This code could be cleaned up. + int end = 0; + unsigned int j; + for(j = startPos; j>0; j--) + { + char ch = styler.SafeGetCharAt(j); + char chPrev = styler.SafeGetCharAt(j-1); + int style = styler.StyleAt(j); + int stylePrev = styler.StyleAt(j-1); + if ((stylePrev != SCE_VHDL_COMMENT) && (stylePrev != SCE_VHDL_STRING)) + { + if(IsAWordChar(chPrev) && !IsAWordChar(ch)) + { + end = j-1; + } + } + if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING)) + { + if(!IsAWordChar(chPrev) && IsAWordStart(ch) && (end != 0)) + { + char s[32]; + unsigned int k; + for(k=0; (k<31 ) && (k<end-j+1 ); k++) { + s[k] = static_cast<char>(tolower(styler[j+k])); + } + s[k] = '\0'; + + if(keywords.InList(s)) { + strcpy(prevWord, s); + break; + } + } + } + } + for(j=j+strlen(prevWord); j<endPos; j++) + { + char ch = styler.SafeGetCharAt(j); + int style = styler.StyleAt(j); + if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING)) + { + if((ch == ';') && (strcmp(prevWord, "end") == 0)) + { + strcpy(prevWord, ";"); + } + } + } + + char chNext = styler[startPos]; + char chPrev = '\0'; + char chNextNonBlank; + int styleNext = styler.StyleAt(startPos); + int style = initStyle; + //Platform::DebugPrintf("Line[%04d] Prev[%20s] ************************* Level[%x]\n", lineCurrent+1, prevWord, levelCurrent); + + /***************************************/ + for (unsigned int i = startPos; i < endPos; i++) + { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + chPrev = styler.SafeGetCharAt(i - 1); + chNextNonBlank = chNext; + unsigned int j = i+1; + while(IsABlank(chNextNonBlank) && j<endPos) + { + j ++ ; + chNextNonBlank = styler.SafeGetCharAt(j); + } + style = styleNext; + styleNext = styler.StyleAt(i + 1); + bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); + + if (foldComment && atEOL && IsCommentLine(lineCurrent, styler)) + { + if(!IsCommentLine(lineCurrent-1, styler) && IsCommentLine(lineCurrent+1, styler)) + { + levelNext++; + } + else if(IsCommentLine(lineCurrent-1, styler) && !IsCommentLine(lineCurrent+1, styler)) + { + levelNext--; + } + } + + if ((style == SCE_VHDL_OPERATOR) && foldAtParenthese) + { + if(ch == '(') { + levelNext++; + } else if (ch == ')') { + levelNext--; + } + } + + if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING)) + { + if((ch == ';') && (strcmp(prevWord, "end") == 0)) + { + strcpy(prevWord, ";"); + } + + if(!IsAWordChar(chPrev) && IsAWordStart(ch)) + { + lastStart = i; + } + + if(iswordchar(ch) && !iswordchar(chNext)) { + char s[32]; + unsigned int k; + for(k=0; (k<31 ) && (k<i-lastStart+1 ); k++) { + s[k] = static_cast<char>(tolower(styler[lastStart+k])); + } + s[k] = '\0'; + + if(keywords.InList(s)) + { + if ( + strcmp(s, "architecture") == 0 || + strcmp(s, "case") == 0 || + strcmp(s, "component") == 0 || + strcmp(s, "entity") == 0 || + strcmp(s, "generate") == 0 || + strcmp(s, "loop") == 0 || + strcmp(s, "package") ==0 || + strcmp(s, "process") == 0 || + strcmp(s, "record") == 0 || + strcmp(s, "then") == 0) + { + if (strcmp(prevWord, "end") != 0) + { + if (levelMinCurrentElse > levelNext) { + levelMinCurrentElse = levelNext; + } + levelNext++; + } + } else if ( + strcmp(s, "procedure") == 0 || + strcmp(s, "function") == 0) + { + if (strcmp(prevWord, "end") != 0) // check for "end procedure" etc. + { // This code checks to see if the procedure / function is a definition within a "package" + // rather than the actual code in the body. + int BracketLevel = 0; + for(int j=i+1; j<styler.Length(); j++) + { + int LocalStyle = styler.StyleAt(j); + char LocalCh = styler.SafeGetCharAt(j); + if(LocalCh == '(') BracketLevel++; + if(LocalCh == ')') BracketLevel--; + if( + (BracketLevel == 0) && + (LocalStyle != SCE_VHDL_COMMENT) && + (LocalStyle != SCE_VHDL_STRING) && + !iswordchar(styler.SafeGetCharAt(j-1)) && + styler.Match(j, "is") && + !iswordchar(styler.SafeGetCharAt(j+2))) + { + if (levelMinCurrentElse > levelNext) { + levelMinCurrentElse = levelNext; + } + levelNext++; + break; + } + if((BracketLevel == 0) && (LocalCh == ';')) + { + break; + } + } + } + + } else if (strcmp(s, "end") == 0) { + levelNext--; + } else if(strcmp(s, "elsif") == 0) { // elsif is followed by then so folding occurs correctly + levelNext--; + } else if (strcmp(s, "else") == 0) { + if(strcmp(prevWord, "when") != 0) // ignore a <= x when y else z; + { + levelMinCurrentElse = levelNext - 1; // VHDL else is all on its own so just dec. the min level + } + } else if( + ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "architecture") == 0)) || + ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "function") == 0)) || + ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "procedure") == 0))) + { + levelMinCurrentBegin = levelNext - 1; + } + //Platform::DebugPrintf("Line[%04d] Prev[%20s] Cur[%20s] Level[%x]\n", lineCurrent+1, prevWord, s, levelCurrent); + strcpy(prevWord, s); + } + } + } + if (atEOL) { + int levelUse = levelCurrent; + + if (foldAtElse && (levelMinCurrentElse < levelUse)) { + levelUse = levelMinCurrentElse; + } + if (foldAtBegin && (levelMinCurrentBegin < levelUse)) { + levelUse = levelMinCurrentBegin; + } + int lev = levelUse | levelNext << 16; + if (visibleChars == 0 && foldCompact) + lev |= SC_FOLDLEVELWHITEFLAG; + + if (levelUse < levelNext) + lev |= SC_FOLDLEVELHEADERFLAG; + if (lev != styler.LevelAt(lineCurrent)) { + styler.SetLevel(lineCurrent, lev); + } + //Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent); + lineCurrent++; + levelCurrent = levelNext; + //levelMinCurrent = levelCurrent; + levelMinCurrentElse = levelCurrent; + levelMinCurrentBegin = levelCurrent; + visibleChars = 0; + } + /***************************************/ + if (!isspacechar(ch)) visibleChars++; + } + + /***************************************/ +// Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent); +} + +//============================================================================= +static void FoldVHDLDoc(unsigned int startPos, int length, int initStyle, WordList *[], + Accessor &styler) { + FoldNoBoxVHDLDoc(startPos, length, initStyle, styler); +} + +//============================================================================= +static const char * const VHDLWordLists[] = { + "Keywords", + "Operators", + "Attributes", + "Standard Functions", + "Standard Packages", + "Standard Types", + "User Words", + 0, + }; + + +LexerModule lmVHDL(SCLEX_VHDL, ColouriseVHDLDoc, "vhdl", FoldVHDLDoc, VHDLWordLists); + + +// Keyword: +// access after alias all architecture array assert attribute begin block body buffer bus case component +// configuration constant disconnect downto else elsif end entity exit file for function generate generic +// group guarded if impure in inertial inout is label library linkage literal loop map new next null of +// on open others out package port postponed procedure process pure range record register reject report +// return select severity shared signal subtype then to transport type unaffected units until use variable +// wait when while with +// +// Operators: +// abs and mod nand nor not or rem rol ror sla sll sra srl xnor xor +// +// Attributes: +// left right low high ascending image value pos val succ pred leftof rightof base range reverse_range +// length delayed stable quiet transaction event active last_event last_active last_value driving +// driving_value simple_name path_name instance_name +// +// Std Functions: +// now readline read writeline write endfile resolved to_bit to_bitvector to_stdulogic to_stdlogicvector +// to_stdulogicvector to_x01 to_x01z to_UX01 rising_edge falling_edge is_x shift_left shift_right rotate_left +// rotate_right resize to_integer to_unsigned to_signed std_match to_01 +// +// Std Packages: +// std ieee work standard textio std_logic_1164 std_logic_arith std_logic_misc std_logic_signed +// std_logic_textio std_logic_unsigned numeric_bit numeric_std math_complex math_real vital_primitives +// vital_timing +// +// Std Types: +// boolean bit character severity_level integer real time delay_length natural positive string bit_vector +// file_open_kind file_open_status line text side width std_ulogic std_ulogic_vector std_logic +// std_logic_vector X01 X01Z UX01 UX01Z unsigned signed +// + |