in ext/scintilla/lexers/LexVerilog.cxx [397:764]
void SCI_METHOD LexerVerilog::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess)
{
LexAccessor styler(pAccess);
const int kwOther=0, kwDot=0x100, kwInput=0x200, kwOutput=0x300, kwInout=0x400, kwProtected=0x800;
int lineState = kwOther;
bool continuationLine = false;
Sci_Position curLine = styler.GetLine(startPos);
if (curLine > 0) lineState = styler.GetLineState(curLine - 1);
// Do not leak onto next line
if (initStyle == SCE_V_STRINGEOL)
initStyle = SCE_V_DEFAULT;
if ((MaskActive(initStyle) == SCE_V_PREPROCESSOR) ||
(MaskActive(initStyle) == SCE_V_COMMENTLINE) ||
(MaskActive(initStyle) == SCE_V_COMMENTLINEBANG)) {
// Set continuationLine if last character of previous line is '\'
if (curLine > 0) {
Sci_Position endLinePrevious = styler.LineEnd(curLine - 1);
if (endLinePrevious > 0) {
continuationLine = styler.SafeGetCharAt(endLinePrevious-1) == '\\';
}
}
}
StyleContext sc(startPos, length, initStyle, styler);
LinePPState preproc = vlls.ForLine(curLine);
bool definitionsChanged = false;
// Truncate ppDefineHistory before current line
if (!options.updatePreprocessor)
ppDefineHistory.clear();
std::vector<PPDefinition>::iterator itInvalid = std::find_if(ppDefineHistory.begin(), ppDefineHistory.end(), After(curLine-1));
if (itInvalid != ppDefineHistory.end()) {
ppDefineHistory.erase(itInvalid, ppDefineHistory.end());
definitionsChanged = true;
}
SymbolTable preprocessorDefinitions = preprocessorDefinitionsStart;
for (std::vector<PPDefinition>::iterator itDef = ppDefineHistory.begin(); itDef != ppDefineHistory.end(); ++itDef) {
if (itDef->isUndef)
preprocessorDefinitions.erase(itDef->key);
else
preprocessorDefinitions[itDef->key] = SymbolValue(itDef->value, itDef->arguments);
}
int activitySet = preproc.IsInactive() ? activeFlag : 0;
Sci_Position lineEndNext = styler.LineEnd(curLine);
bool isEscapedId = false; // true when parsing an escaped Identifier
bool isProtected = (lineState&kwProtected) != 0; // true when parsing a protected region
for (; sc.More(); sc.Forward()) {
if (sc.atLineStart) {
if (sc.state == SCE_V_STRING) {
// Prevent SCE_V_STRINGEOL from leaking back to previous line
sc.SetState(SCE_V_STRING);
}
if ((MaskActive(sc.state) == SCE_V_PREPROCESSOR) && (!continuationLine)) {
sc.SetState(SCE_V_DEFAULT|activitySet);
}
if (preproc.IsInactive()) {
activitySet = activeFlag;
sc.SetState(sc.state | activitySet);
}
}
if (sc.atLineEnd) {
curLine++;
lineEndNext = styler.LineEnd(curLine);
vlls.Add(curLine, preproc);
// Update the line state, so it can be seen by next line
styler.SetLineState(curLine, lineState);
isEscapedId = false; // EOL terminates an escaped Identifier
}
// Handle line continuation generically.
if (sc.ch == '\\') {
if (static_cast<Sci_Position>((sc.currentPos+1)) >= lineEndNext) {
curLine++;
lineEndNext = styler.LineEnd(curLine);
vlls.Add(curLine, preproc);
// Update the line state, so it can be seen by next line
styler.SetLineState(curLine, lineState);
sc.Forward();
if (sc.ch == '\r' && sc.chNext == '\n') {
// Even in UTF-8, \r and \n are separate
sc.Forward();
}
continuationLine = true;
sc.Forward();
continue;
}
}
// for comment keyword
if (MaskActive(sc.state) == SCE_V_COMMENT_WORD && !IsAWordChar(sc.ch)) {
char s[100];
int state = lineState & 0xff;
sc.GetCurrent(s, sizeof(s));
if (keywords5.InList(s)) {
sc.ChangeState(SCE_V_COMMENT_WORD|activitySet);
} else {
sc.ChangeState(state|activitySet);
}
sc.SetState(state|activitySet);
}
const bool atLineEndBeforeSwitch = sc.atLineEnd;
// Determine if the current state should terminate.
switch (MaskActive(sc.state)) {
case SCE_V_OPERATOR:
sc.SetState(SCE_V_DEFAULT|activitySet);
break;
case SCE_V_NUMBER:
if (!(IsAWordChar(sc.ch) || (sc.ch == '?'))) {
sc.SetState(SCE_V_DEFAULT|activitySet);
}
break;
case SCE_V_IDENTIFIER:
if (!isEscapedId &&(!IsAWordChar(sc.ch) || (sc.ch == '.'))) {
char s[100];
lineState &= 0xff00;
sc.GetCurrent(s, sizeof(s));
if (options.portStyling && (strcmp(s, "input") == 0)) {
lineState = kwInput;
sc.ChangeState(SCE_V_INPUT|activitySet);
} else if (options.portStyling && (strcmp(s, "output") == 0)) {
lineState = kwOutput;
sc.ChangeState(SCE_V_OUTPUT|activitySet);
} else if (options.portStyling && (strcmp(s, "inout") == 0)) {
lineState = kwInout;
sc.ChangeState(SCE_V_INOUT|activitySet);
} else if (lineState == kwInput) {
sc.ChangeState(SCE_V_INPUT|activitySet);
} else if (lineState == kwOutput) {
sc.ChangeState(SCE_V_OUTPUT|activitySet);
} else if (lineState == kwInout) {
sc.ChangeState(SCE_V_INOUT|activitySet);
} else if (lineState == kwDot) {
lineState = kwOther;
if (options.portStyling)
sc.ChangeState(SCE_V_PORT_CONNECT|activitySet);
} else if (keywords.InList(s)) {
sc.ChangeState(SCE_V_WORD|activitySet);
} else if (keywords2.InList(s)) {
sc.ChangeState(SCE_V_WORD2|activitySet);
} else if (keywords3.InList(s)) {
sc.ChangeState(SCE_V_WORD3|activitySet);
} else if (keywords4.InList(s)) {
sc.ChangeState(SCE_V_USER|activitySet);
} else if (options.allUppercaseDocKeyword && AllUpperCase(s)) {
sc.ChangeState(SCE_V_USER|activitySet);
}
sc.SetState(SCE_V_DEFAULT|activitySet);
}
break;
case SCE_V_PREPROCESSOR:
if (!IsAWordChar(sc.ch) || sc.atLineEnd) {
sc.SetState(SCE_V_DEFAULT|activitySet);
}
break;
case SCE_V_COMMENT:
if (sc.Match('*', '/')) {
sc.Forward();
sc.ForwardSetState(SCE_V_DEFAULT|activitySet);
} else if (IsAWordStart(sc.ch)) {
lineState = sc.state | (lineState & 0xff00);
sc.SetState(SCE_V_COMMENT_WORD|activitySet);
}
break;
case SCE_V_COMMENTLINE:
case SCE_V_COMMENTLINEBANG:
if (sc.atLineStart) {
sc.SetState(SCE_V_DEFAULT|activitySet);
} else if (IsAWordStart(sc.ch)) {
lineState = sc.state | (lineState & 0xff00);
sc.SetState(SCE_V_COMMENT_WORD|activitySet);
}
break;
case SCE_V_STRING:
if (sc.ch == '\\') {
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
sc.Forward();
}
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_V_DEFAULT|activitySet);
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_V_STRINGEOL|activitySet);
sc.ForwardSetState(SCE_V_DEFAULT|activitySet);
}
break;
}
if (sc.atLineEnd && !atLineEndBeforeSwitch) {
// State exit processing consumed characters up to end of line.
curLine++;
lineEndNext = styler.LineEnd(curLine);
vlls.Add(curLine, preproc);
// Update the line state, so it can be seen by next line
styler.SetLineState(curLine, lineState);
isEscapedId = false; // EOL terminates an escaped Identifier
}
// Determine if a new state should be entered.
if (MaskActive(sc.state) == SCE_V_DEFAULT) {
if (sc.ch == '`') {
sc.SetState(SCE_V_PREPROCESSOR|activitySet);
// Skip whitespace between ` and preprocessor word
do {
sc.Forward();
} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
if (sc.atLineEnd) {
sc.SetState(SCE_V_DEFAULT|activitySet);
styler.SetLineState(curLine, lineState);
} else {
if (sc.Match("protected")) {
isProtected = true;
lineState |= kwProtected;
styler.SetLineState(curLine, lineState);
} else if (sc.Match("endprotected")) {
isProtected = false;
lineState &= ~kwProtected;
styler.SetLineState(curLine, lineState);
} else if (!isProtected && options.trackPreprocessor) {
if (sc.Match("ifdef") || sc.Match("ifndef")) {
bool isIfDef = sc.Match("ifdef");
int i = isIfDef ? 5 : 6;
std::string restOfLine = GetRestOfLine(styler, sc.currentPos + i + 1, false);
bool foundDef = preprocessorDefinitions.find(restOfLine) != preprocessorDefinitions.end();
preproc.StartSection(isIfDef == foundDef);
} else if (sc.Match("else")) {
if (!preproc.CurrentIfTaken()) {
preproc.InvertCurrentLevel();
activitySet = preproc.IsInactive() ? activeFlag : 0;
if (!activitySet) {
sc.ChangeState(SCE_V_PREPROCESSOR|activitySet);
}
} else if (!preproc.IsInactive()) {
preproc.InvertCurrentLevel();
activitySet = preproc.IsInactive() ? activeFlag : 0;
if (!activitySet) {
sc.ChangeState(SCE_V_PREPROCESSOR|activitySet);
}
}
} else if (sc.Match("elsif")) {
// Ensure only one chosen out of `if .. `elsif .. `elsif .. `else .. `endif
if (!preproc.CurrentIfTaken()) {
// Similar to `ifdef
std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 6, true);
bool ifGood = preprocessorDefinitions.find(restOfLine) != preprocessorDefinitions.end();
if (ifGood) {
preproc.InvertCurrentLevel();
activitySet = preproc.IsInactive() ? activeFlag : 0;
if (!activitySet)
sc.ChangeState(SCE_V_PREPROCESSOR|activitySet);
}
} else if (!preproc.IsInactive()) {
preproc.InvertCurrentLevel();
activitySet = preproc.IsInactive() ? activeFlag : 0;
if (!activitySet)
sc.ChangeState(SCE_V_PREPROCESSOR|activitySet);
}
} else if (sc.Match("endif")) {
preproc.EndSection();
activitySet = preproc.IsInactive() ? activeFlag : 0;
sc.ChangeState(SCE_V_PREPROCESSOR|activitySet);
} else if (sc.Match("define")) {
if (options.updatePreprocessor && !preproc.IsInactive()) {
std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 6, true);
size_t startName = 0;
while ((startName < restOfLine.length()) && IsSpaceOrTab(restOfLine[startName]))
startName++;
size_t endName = startName;
while ((endName < restOfLine.length()) && setWord.Contains(static_cast<unsigned char>(restOfLine[endName])))
endName++;
std::string key = restOfLine.substr(startName, endName-startName);
if ((endName < restOfLine.length()) && (restOfLine.at(endName) == '(')) {
// Macro
size_t endArgs = endName;
while ((endArgs < restOfLine.length()) && (restOfLine[endArgs] != ')'))
endArgs++;
std::string args = restOfLine.substr(endName + 1, endArgs - endName - 1);
size_t startValue = endArgs+1;
while ((startValue < restOfLine.length()) && IsSpaceOrTab(restOfLine[startValue]))
startValue++;
std::string value;
if (startValue < restOfLine.length())
value = restOfLine.substr(startValue);
preprocessorDefinitions[key] = SymbolValue(value, args);
ppDefineHistory.push_back(PPDefinition(curLine, key, value, false, args));
definitionsChanged = true;
} else {
// Value
size_t startValue = endName;
while ((startValue < restOfLine.length()) && IsSpaceOrTab(restOfLine[startValue]))
startValue++;
std::string value = restOfLine.substr(startValue);
preprocessorDefinitions[key] = value;
ppDefineHistory.push_back(PPDefinition(curLine, key, value));
definitionsChanged = true;
}
}
} else if (sc.Match("undefineall")) {
if (options.updatePreprocessor && !preproc.IsInactive()) {
// remove all preprocessor definitions
std::map<std::string, SymbolValue>::iterator itDef;
for(itDef = preprocessorDefinitions.begin(); itDef != preprocessorDefinitions.end(); ++itDef) {
ppDefineHistory.push_back(PPDefinition(curLine, itDef->first, "", true));
}
preprocessorDefinitions.clear();
definitionsChanged = true;
}
} else if (sc.Match("undef")) {
if (options.updatePreprocessor && !preproc.IsInactive()) {
std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 5, true);
std::vector<std::string> tokens = Tokenize(restOfLine);
std::string key;
if (tokens.size() >= 1) {
key = tokens[0];
preprocessorDefinitions.erase(key);
ppDefineHistory.push_back(PPDefinition(curLine, key, "", true));
definitionsChanged = true;
}
}
}
}
}
} else if (!isProtected) {
if (IsADigit(sc.ch) || (sc.ch == '\'') || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_V_NUMBER|activitySet);
} else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_V_IDENTIFIER|activitySet);
} else if (sc.Match('/', '*')) {
sc.SetState(SCE_V_COMMENT|activitySet);
sc.Forward(); // Eat the * so it isn't used for the end of the comment
} else if (sc.Match('/', '/')) {
if (sc.Match("//!")) // Nice to have a different comment style
sc.SetState(SCE_V_COMMENTLINEBANG|activitySet);
else
sc.SetState(SCE_V_COMMENTLINE|activitySet);
} else if (sc.ch == '\"') {
sc.SetState(SCE_V_STRING|activitySet);
} else if (sc.ch == '\\') {
// escaped identifier, everything is ok up to whitespace
isEscapedId = true;
sc.SetState(SCE_V_IDENTIFIER|activitySet);
} else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '#') {
sc.SetState(SCE_V_OPERATOR|activitySet);
if (sc.ch == '.') lineState = kwDot;
if (sc.ch == ';') lineState = kwOther;
}
}
}
if (isEscapedId && isspacechar(sc.ch)) {
isEscapedId = false;
}
}
if (definitionsChanged) {
styler.ChangeLexerState(startPos, startPos + length);
}
sc.Complete();
}