123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- // 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 <string.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <assert.h>
- #include <ctype.h>
- #include <string>
- #include "ILexer.h"
- #include "Scintilla.h"
- #include "SciLexer.h"
- #include "WordList.h"
- #include "LexAccessor.h"
- #include "Accessor.h"
- #include "StyleContext.h"
- #include "CharacterSet.h"
- #include "LexerModule.h"
- #ifdef SCI_NAMESPACE
- using namespace Scintilla;
- #endif
- /*
- * Interface
- */
- static void ColouriseDocument(
- Sci_PositionU startPos,
- Sci_Position 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 IsSeparatorOrDelimiterCharacter(int ch);
- static bool IsValidIdentifier(const std::string& identifier);
- static bool IsValidNumber(const std::string& 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();
- std::string 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;
- std::string 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);
- std::string 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(
- Sci_PositionU startPos,
- Sci_Position length,
- int initStyle,
- WordList *keywordlists[],
- Accessor &styler) {
- WordList &keywords = *keywordlists[0];
- StyleContext sc(startPos, length, initStyle, styler);
- Sci_Position 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 (IsASpace(sc.ch)) {
- ColouriseWhiteSpace(sc, apostropheStartsAttribute);
- // Delimiters
- } else if (IsDelimiterCharacter(sc.ch)) {
- ColouriseDelimiter(sc, apostropheStartsAttribute);
- // Numbers
- } else if (IsADigit(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 IsSeparatorOrDelimiterCharacter(int ch) {
- return IsASpace(ch) || IsDelimiterCharacter(ch);
- }
- static bool IsValidIdentifier(const std::string& 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 std::string& number) {
- size_t hashPos = number.find("#");
- bool seenDot = false;
- size_t i = 0;
- size_t length = number.length();
- if (length == 0)
- return false; // Just in case
- // Decimal number
- if (hashPos == std::string::npos) {
- 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 (IsADigit(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 (IsADigit(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 (IsADigit(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 (IsADigit(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) || IsADigit(ch);
- }
- static inline bool IsWordStartCharacter(int ch) {
- return (IsASCII(ch) && isalpha(ch)) || ch == '_';
- }
|