summaryrefslogtreecommitdiffstats
path: root/src/LexVHDL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/LexVHDL.cpp')
-rwxr-xr-xsrc/LexVHDL.cpp473
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 <neilh@scintilla.org>
+// 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
+//
+