226 lines
4.9 KiB
C++
226 lines
4.9 KiB
C++
// Scintilla source code edit control
|
|
/** @file LexMaxima.cxx
|
|
** Lexer for Maxima (http://maxima.sourceforge.net).
|
|
** Written by Gunter Königsmann based on the lisp lexer by Alexey Yutkin and Neil Hodgson .
|
|
**/
|
|
// Copyright 2018 by Gunter Königsmann <wxMaxima@physikbuch.de>
|
|
// 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 <string_view>
|
|
|
|
#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"
|
|
using namespace Lexilla;
|
|
|
|
static inline bool isMaximaoperator(char ch) {
|
|
return (ch == '\'' || ch == '`' || ch == '(' ||
|
|
ch == ')' || ch == '[' || ch == ']' ||
|
|
ch == '{' || ch == '}' || ch == '!' ||
|
|
ch == '*' || ch == '/' || ch == '^' ||
|
|
ch == ',' || ch == ':' || ch == '+' ||
|
|
ch == '-');
|
|
}
|
|
|
|
static void ColouriseMaximaDoc(Sci_PositionU startPos, Sci_Position length, int lastStyle,
|
|
WordList *[],
|
|
Accessor &styler) {
|
|
|
|
styler.StartAt(startPos);
|
|
|
|
Sci_PositionU lengthDoc = startPos + length;
|
|
styler.StartSegment(startPos);
|
|
|
|
Sci_PositionU i = startPos;
|
|
|
|
// If we are in the middle of a comment we go back to its start before highlighting
|
|
if(lastStyle == SCE_MAXIMA_COMMENT)
|
|
{
|
|
while((i>0) &&
|
|
!((styler.SafeGetCharAt(i+1) == '*') && (styler.SafeGetCharAt(i) == '/')))
|
|
i--;
|
|
}
|
|
|
|
for (; i < lengthDoc; i++) {
|
|
char ch = styler.SafeGetCharAt(i);
|
|
char chNext = styler.SafeGetCharAt(i + 1);
|
|
|
|
if (styler.IsLeadByte(ch))
|
|
continue;
|
|
|
|
// Handle comments.
|
|
// Comments start with /* and end with */
|
|
if((ch == '/') && (chNext == '*'))
|
|
{
|
|
i++;i++;
|
|
|
|
chNext = styler.SafeGetCharAt(i);
|
|
for (; i < lengthDoc; i++)
|
|
{
|
|
ch = chNext;
|
|
chNext = styler.SafeGetCharAt(i + 1);
|
|
if((ch == '*') && (chNext == '/'))
|
|
{
|
|
i++;
|
|
i++;
|
|
break;
|
|
}
|
|
}
|
|
if(i > lengthDoc)
|
|
i = lengthDoc;
|
|
i--;
|
|
styler.ColourTo(i, SCE_MAXIMA_COMMENT);
|
|
continue;
|
|
}
|
|
|
|
// Handle Operators
|
|
if(isMaximaoperator(ch))
|
|
{
|
|
styler.ColourTo(i, SCE_MAXIMA_OPERATOR);
|
|
continue;
|
|
}
|
|
|
|
// Handle command endings.
|
|
if((ch == '$') || (ch == ';'))
|
|
{
|
|
styler.ColourTo(i, SCE_MAXIMA_COMMANDENDING);
|
|
continue;
|
|
}
|
|
|
|
// Handle numbers. Numbers always begin with a digit.
|
|
if(IsASCII(ch) && isdigit(ch))
|
|
{
|
|
i++;
|
|
for (; i < lengthDoc; i++)
|
|
{
|
|
ch = chNext;
|
|
chNext = styler.SafeGetCharAt(i + 1);
|
|
|
|
if(ch == '.')
|
|
continue;
|
|
|
|
// A "e" or similar can be followed by a "+" or a "-"
|
|
if(((ch == 'e') || (ch == 'b') || (ch == 'g') || (ch == 'f')) &&
|
|
((chNext == '+') || (chNext == '-')))
|
|
{
|
|
i++;
|
|
chNext = styler.SafeGetCharAt(i + 1);
|
|
continue;
|
|
}
|
|
|
|
if(!IsASCII(ch) || !(isdigit(ch) || islower(ch) || isupper(ch)))
|
|
{
|
|
i--;
|
|
break;
|
|
}
|
|
}
|
|
styler.ColourTo(i, SCE_MAXIMA_NUMBER);
|
|
continue;
|
|
}
|
|
|
|
// Handle strings
|
|
if(ch == '\"')
|
|
{
|
|
i++;
|
|
for (; i < lengthDoc; i++)
|
|
{
|
|
ch = chNext;
|
|
chNext = styler.SafeGetCharAt(i + 1);
|
|
if(ch == '\\')
|
|
i++;
|
|
else
|
|
{
|
|
if(ch == '\"')
|
|
break;
|
|
}
|
|
}
|
|
styler.ColourTo(i, SCE_MAXIMA_STRING);
|
|
continue;
|
|
}
|
|
|
|
// Handle keywords. Maxima treats Non-ASCII chars as ordinary letters.
|
|
if(((!IsASCII(ch))) || isalpha(ch) || (ch == '_'))
|
|
{
|
|
char cmd[100];
|
|
int cmdidx = 0;
|
|
memset(cmd,0,100);
|
|
cmd[cmdidx++] = ch;
|
|
i++;
|
|
for (; i < lengthDoc; i++)
|
|
{
|
|
ch = chNext;
|
|
chNext = styler.SafeGetCharAt(i + 1);
|
|
if(ch == '\\')
|
|
{
|
|
if(cmdidx < 99)
|
|
cmd[cmdidx++] = ch;
|
|
i++;
|
|
if(cmdidx < 99)
|
|
cmd[cmdidx++] = ch;
|
|
continue;
|
|
}
|
|
if(isMaximaoperator(ch) || ((IsASCII(ch) && !isalpha(ch) && !isdigit(ch) && (ch != '_'))))
|
|
{
|
|
i--;
|
|
break;
|
|
}
|
|
if(cmdidx < 99)
|
|
cmd[cmdidx++] = ch;
|
|
}
|
|
|
|
// A few known keywords
|
|
if(
|
|
(strncmp(cmd,"if",99) == 0) ||
|
|
(strncmp(cmd,"then",99) == 0) ||
|
|
(strncmp(cmd,"else",99) == 0) ||
|
|
(strncmp(cmd,"thru",99) == 0) ||
|
|
(strncmp(cmd,"for",99) == 0) ||
|
|
(strncmp(cmd,"while",99) == 0) ||
|
|
(strncmp(cmd,"do",99) == 0)
|
|
)
|
|
{
|
|
styler.ColourTo(i, SCE_MAXIMA_COMMAND);
|
|
continue;
|
|
}
|
|
|
|
// All other keywords are functions if they are followed
|
|
// by an opening parenthesis
|
|
char nextNonwhitespace = ' ';
|
|
for (Sci_PositionU o = i + 1; o < lengthDoc; o++)
|
|
{
|
|
nextNonwhitespace = styler.SafeGetCharAt(o);
|
|
if(!IsASCII(nextNonwhitespace) || !isspacechar(nextNonwhitespace))
|
|
break;
|
|
}
|
|
if(nextNonwhitespace == '(')
|
|
{
|
|
styler.ColourTo(i, SCE_MAXIMA_COMMAND);
|
|
}
|
|
else
|
|
{
|
|
styler.ColourTo(i, SCE_MAXIMA_VARIABLE);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
styler.ColourTo(i-1, SCE_MAXIMA_UNKNOWN);
|
|
}
|
|
}
|
|
|
|
LexerModule lmMaxima(SCLEX_MAXIMA, ColouriseMaximaDoc, "maxima", 0, 0);
|