Logo Search packages:      
Sourcecode: wxwindows2.4 version File versions

LexAda.cxx

Go to the documentation of this file.
// Scintilla source code edit control
/** @file LexAda.cxx
 ** Lexer for Ada 95
 **/
// Copyright 2002 by Sergey Koshcheyev <sergey.k@seznam.cz>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>

#include "Platform.h"

#include "Accessor.h"
#include "StyleContext.h"
#include "PropSet.h"
#include "KeyWords.h"
#include "SciLexer.h"
#include "SString.h"

/*
 * Interface
 */

static void ColouriseDocument(
    unsigned int startPos,
    int length,
    int initStyle,
    WordList *keywordlists[],
    Accessor &styler);

static const char * const adaWordListDesc[] = {
      "Keywords",
      0
};

LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada", NULL, adaWordListDesc);

/*
 * Implementation
 */

// Functions that have apostropheStartsAttribute as a parameter set it according to whether
// an apostrophe encountered after processing the current token will start an attribute or
// a character literal.
static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL);
static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);

static inline bool IsDelimiterCharacter(int ch);
static inline bool IsNumberStartCharacter(int ch);
static inline bool IsNumberCharacter(int ch);
static inline bool IsSeparatorOrDelimiterCharacter(int ch);
static bool IsValidIdentifier(const SString& identifier);
static bool IsValidNumber(const SString& number);
static inline bool IsWordStartCharacter(int ch);
static inline bool IsWordCharacter(int ch);

static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute) {
      apostropheStartsAttribute = true;

      sc.SetState(SCE_ADA_CHARACTER);

      // Skip the apostrophe and one more character (so that '' is shown as non-terminated and '''
      // is handled correctly)
      sc.Forward();
      sc.Forward();

      ColouriseContext(sc, '\'', SCE_ADA_CHARACTEREOL);
}

static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL) {
      while (!sc.atLineEnd && !sc.Match(chEnd)) {
            sc.Forward();
      }

      if (!sc.atLineEnd) {
            sc.ForwardSetState(SCE_ADA_DEFAULT);
      } else {
            sc.ChangeState(stateEOL);
      }
}

static void ColouriseComment(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
      // Apostrophe meaning is not changed, but the parameter is present for uniformity

      sc.SetState(SCE_ADA_COMMENTLINE);

      while (!sc.atLineEnd) {
            sc.Forward();
      }
}

static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
      apostropheStartsAttribute = sc.Match (')');
      sc.SetState(SCE_ADA_DELIMITER);
      sc.ForwardSetState(SCE_ADA_DEFAULT);
}

static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
      apostropheStartsAttribute = false;

      sc.SetState(SCE_ADA_LABEL);

      // Skip "<<"
      sc.Forward();
      sc.Forward();

      SString identifier;

      while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
            identifier += static_cast<char>(tolower(sc.ch));
            sc.Forward();
      }

      // Skip ">>"
      if (sc.Match('>', '>')) {
            sc.Forward();
            sc.Forward();
      } else {
            sc.ChangeState(SCE_ADA_ILLEGAL);
      }

      // If the name is an invalid identifier or a keyword, then make it invalid label
      if (!IsValidIdentifier(identifier) || keywords.InList(identifier.c_str())) {
            sc.ChangeState(SCE_ADA_ILLEGAL);
      }

      sc.SetState(SCE_ADA_DEFAULT);

}

static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
      apostropheStartsAttribute = true;

      SString number;
      sc.SetState(SCE_ADA_NUMBER);

      // Get all characters up to a delimiter or a separator, including points, but excluding
      // double points (ranges).
      while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
            number += static_cast<char>(sc.ch);
            sc.Forward();
      }

      // Special case: exponent with sign
      if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
              (sc.ch == '+' || sc.ch == '-')) {
            number += static_cast<char>(sc.ch);
            sc.Forward ();

            while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
                  number += static_cast<char>(sc.ch);
                  sc.Forward();
            }
      }

      if (!IsValidNumber(number)) {
            sc.ChangeState(SCE_ADA_ILLEGAL);
      }

      sc.SetState(SCE_ADA_DEFAULT);
}

static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute) {
      apostropheStartsAttribute = true;

      sc.SetState(SCE_ADA_STRING);
      sc.Forward();

      ColouriseContext(sc, '"', SCE_ADA_STRINGEOL);
}

static void ColouriseWhiteSpace(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
      // Apostrophe meaning is not changed, but the parameter is present for uniformity
      sc.SetState(SCE_ADA_DEFAULT);
      sc.ForwardSetState(SCE_ADA_DEFAULT);
}

static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
      apostropheStartsAttribute = true;
      sc.SetState(SCE_ADA_IDENTIFIER);

      SString word;

      while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
            word += static_cast<char>(tolower(sc.ch));
            sc.Forward();
      }

      if (!IsValidIdentifier(word)) {
            sc.ChangeState(SCE_ADA_ILLEGAL);

      } else if (keywords.InList(word.c_str())) {
            sc.ChangeState(SCE_ADA_WORD);

            if (word != "all") {
                  apostropheStartsAttribute = false;
            }
      }

      sc.SetState(SCE_ADA_DEFAULT);
}

//
// ColouriseDocument
//

static void ColouriseDocument(
    unsigned int startPos,
    int length,
    int initStyle,
    WordList *keywordlists[],
    Accessor &styler) {
      WordList &keywords = *keywordlists[0];

      StyleContext sc(startPos, length, initStyle, styler);

      int lineCurrent = styler.GetLine(startPos);
      bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;

      while (sc.More()) {
            if (sc.atLineEnd) {
                  // Go to the next line
                  sc.Forward();
                  lineCurrent++;

                  // Remember the line state for future incremental lexing
                  styler.SetLineState(lineCurrent, apostropheStartsAttribute);

                  // Don't continue any styles on the next line
                  sc.SetState(SCE_ADA_DEFAULT);
            }

            // Comments
            if (sc.Match('-', '-')) {
                  ColouriseComment(sc, apostropheStartsAttribute);

            // Strings
            } else if (sc.Match('"')) {
                  ColouriseString(sc, apostropheStartsAttribute);

            // Characters
            } else if (sc.Match('\'') && !apostropheStartsAttribute) {
                  ColouriseCharacter(sc, apostropheStartsAttribute);

            // Labels
            } else if (sc.Match('<', '<')) {
                  ColouriseLabel(sc, keywords, apostropheStartsAttribute);

            // Whitespace
            } else if (isspace(sc.ch)) {
                  ColouriseWhiteSpace(sc, apostropheStartsAttribute);

            // Delimiters
            } else if (IsDelimiterCharacter(sc.ch)) {
                  ColouriseDelimiter(sc, apostropheStartsAttribute);

            // Numbers
            } else if (isdigit(sc.ch) || sc.ch == '#') {
                  ColouriseNumber(sc, apostropheStartsAttribute);

            // Keywords or identifiers
            } else {
                  ColouriseWord(sc, keywords, apostropheStartsAttribute);
            }
      }

      sc.Complete();
}

static inline bool IsDelimiterCharacter(int ch) {
      switch (ch) {
      case '&':
      case '\'':
      case '(':
      case ')':
      case '*':
      case '+':
      case ',':
      case '-':
      case '.':
      case '/':
      case ':':
      case ';':
      case '<':
      case '=':
      case '>':
      case '|':
            return true;
      default:
            return false;
      }
}

static inline bool IsNumberCharacter(int ch) {
      return IsNumberStartCharacter(ch) ||
             ch == '_' ||
             ch == '.' ||
             ch == '#' ||
             (ch >= 'a' && ch <= 'f') ||
             (ch >= 'A' && ch <= 'F');
}

static inline bool IsNumberStartCharacter(int ch) {
      return isdigit(ch) != 0;
}

static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
      return isspace(ch) || IsDelimiterCharacter(ch);
}

static bool IsValidIdentifier(const SString& identifier) {
      // First character can't be '_', so initialize the flag to true
      bool lastWasUnderscore = true;

      size_t length = identifier.length();

      // Zero-length identifiers are not valid (these can occur inside labels)
      if (length == 0) {
            return false;
      }

      // Check for valid character at the start
      if (!IsWordStartCharacter(identifier[0])) {
            return false;
      }

      // Check for only valid characters and no double underscores
      for (size_t i = 0; i < length; i++) {
            if (!IsWordCharacter(identifier[i]) ||
                    (identifier[i] == '_' && lastWasUnderscore)) {
                  return false;
            }
            lastWasUnderscore = identifier[i] == '_';
      }

      // Check for underscore at the end
      if (lastWasUnderscore == true) {
            return false;
      }

      // All checks passed
      return true;
}

static bool IsValidNumber(const SString& number) {
      int hashPos = number.search("#");
      bool seenDot = false;

      size_t i = 0;
      size_t length = number.length();

      if (length == 0)
            return false; // Just in case

      // Decimal number
      if (hashPos == -1) {
            bool canBeSpecial = false;

            for (; i < length; i++) {
                  if (number[i] == '_') {
                        if (!canBeSpecial) {
                              return false;
                        }
                        canBeSpecial = false;
                  } else if (number[i] == '.') {
                        if (!canBeSpecial || seenDot) {
                              return false;
                        }
                        canBeSpecial = false;
                        seenDot = true;
                  } else if (isdigit(number[i])) {
                        canBeSpecial = true;
                  } else {
                        break;
                  }
            }

            if (!canBeSpecial)
                  return false;
      } else {
            // Based number
            bool canBeSpecial = false;
            int base = 0;

            // Parse base
            for (; i < length; i++) {
                  int ch = number[i];
                  if (ch == '_') {
                        if (!canBeSpecial)
                              return false;
                        canBeSpecial = false;
                  } else if (isdigit (ch)) {
                        base = base * 10 + (ch - '0');
                        if (base > 16)
                              return false;
                        canBeSpecial = true;
                  } else if (ch == '#' && canBeSpecial) {
                        break;
                  } else {
                        return false;
                  }
            }

            if (base < 2)
                  return false;
            if (i == length)
                  return false;

            i++; // Skip over '#'

            // Parse number
            canBeSpecial = false;

            for (; i < length; i++) {
                  int ch = tolower(number[i]);

                  if (ch == '_') {
                        if (!canBeSpecial) {
                              return false;
                        }
                        canBeSpecial = false;

                  } else if (ch == '.') {
                        if (!canBeSpecial || seenDot) {
                              return false;
                        }
                        canBeSpecial = false;
                        seenDot = true;

                  } else if (isdigit (ch)) {
                        if (ch - '0' >= base) {
                              return false;
                        }
                        canBeSpecial = true;

                  } else if (ch >= 'a' && ch <= 'f') {
                        if (ch - 'a' + 10 >= base) {
                              return false;
                        }
                        canBeSpecial = true;

                  } else if (ch == '#' && canBeSpecial) {
                        break;

                  } else {
                        return false;
                  }
            }

            if (i == length) {
                  return false;
            }

            i++;
      }

      // Exponent (optional)
      if (i < length) {
            if (number[i] != 'e' && number[i] != 'E')
                  return false;

            i++; // Move past 'E'

            if (i == length) {
                  return false;
            }

            if (number[i] == '+')
                  i++;
            else if (number[i] == '-') {
                  if (seenDot) {
                        i++;
                  } else {
                        return false; // Integer literals should not have negative exponents
                  }
            }

            if (i == length) {
                  return false;
            }

            bool canBeSpecial = false;

            for (; i < length; i++) {
                  if (number[i] == '_') {
                        if (!canBeSpecial) {
                              return false;
                        }
                        canBeSpecial = false;
                  } else if (isdigit(number[i])) {
                        canBeSpecial = true;
                  } else {
                        return false;
                  }
            }

            if (!canBeSpecial)
                  return false;
      }

      // if i == length, number was parsed successfully.
      return i == length;
}

static inline bool IsWordCharacter(int ch) {
      return IsWordStartCharacter(ch) || isdigit(ch);
}

static inline bool IsWordStartCharacter(int ch) {
      return isalpha(ch) || ch == '_';
}

Generated by  Doxygen 1.6.0   Back to index