16dae3ea06
tl;dr : making Fluid maintainable, no changes in code execution and logic. This is a pretty extensive restructuring of the Fluid source tree. It was neccessary because source and header files were getting much too big to handle. Many source files had no header, and many headers declared functions that were in diffrent source files. Reorganized much of the include statements. Added comments to some of the files. Added Doxygen configuration file for standalone Fluid docs. Tested everything by rebuilding Fluid .fl designs with the resorted version of Fluid.
329 lines
8.8 KiB
C++
329 lines
8.8 KiB
C++
//
|
|
// Syntax highlighting for the Fast Light Tool Kit (FLTK).
|
|
//
|
|
// Copyright 1998-2020 by Bill Spitzak and others.
|
|
// Copyright 2020 Greg Ercolano.
|
|
//
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
// file is missing or damaged, see the license at:
|
|
//
|
|
// https://www.fltk.org/COPYING.php
|
|
//
|
|
// Please see the following page on how to report bugs and issues:
|
|
//
|
|
// https://www.fltk.org/bugs.php
|
|
//
|
|
|
|
#include "StyleParse.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h> // bsearch()
|
|
|
|
// Sorted list of C/C++ keywords...
|
|
static const char * const code_keywords[] = {
|
|
"and",
|
|
"and_eq",
|
|
"asm",
|
|
"bitand",
|
|
"bitor",
|
|
"break",
|
|
"case",
|
|
"catch",
|
|
"compl",
|
|
"continue",
|
|
"default",
|
|
"delete",
|
|
"do",
|
|
"else",
|
|
"false",
|
|
"for",
|
|
"goto",
|
|
"if",
|
|
"new",
|
|
"not",
|
|
"not_eq",
|
|
"operator",
|
|
"or",
|
|
"or_eq",
|
|
"return",
|
|
"switch",
|
|
"template",
|
|
"this",
|
|
"throw",
|
|
"true",
|
|
"try",
|
|
"while",
|
|
"xor",
|
|
"xor_eq"
|
|
};
|
|
|
|
// Sorted list of C/C++ types...
|
|
static const char * const code_types[] = {
|
|
"auto",
|
|
"bool",
|
|
"char",
|
|
"class",
|
|
"const",
|
|
"const_cast",
|
|
"double",
|
|
"dynamic_cast",
|
|
"enum",
|
|
"explicit",
|
|
"extern",
|
|
"float",
|
|
"friend",
|
|
"inline",
|
|
"int",
|
|
"long",
|
|
"mutable",
|
|
"namespace",
|
|
"private",
|
|
"protected",
|
|
"public",
|
|
"register",
|
|
"short",
|
|
"signed",
|
|
"sizeof",
|
|
"static",
|
|
"static_cast",
|
|
"struct",
|
|
"template",
|
|
"typedef",
|
|
"typename",
|
|
"union",
|
|
"unsigned",
|
|
"virtual",
|
|
"void",
|
|
"volatile"
|
|
};
|
|
|
|
// 'compare_keywords()' - Compare two keywords...
|
|
extern "C" {
|
|
static int compare_keywords(const void *a, const void *b) {
|
|
return strcmp(*((const char **)a), *((const char **)b));
|
|
}
|
|
}
|
|
|
|
// See if 'find' is a C/C++ keyword.
|
|
// Refer to bsearch(3) for return value.
|
|
//
|
|
static void* search_keywords(char *find) {
|
|
return bsearch(&find, code_keywords,
|
|
sizeof(code_keywords) / sizeof(code_keywords[0]),
|
|
sizeof(code_keywords[0]), compare_keywords);
|
|
}
|
|
|
|
// See if 'find' is a C/C++ type.
|
|
// Refer to bsearch(3) for return value.
|
|
//
|
|
static void* search_types(char *find) {
|
|
return bsearch(&find, code_types,
|
|
sizeof(code_types) / sizeof(code_types[0]),
|
|
sizeof(code_types[0]), compare_keywords);
|
|
}
|
|
|
|
// Handle style parsing over a character
|
|
// Handles updating col counter when \n encountered.
|
|
// Applies the current style, advances to next text + style char.
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_over_char(int handle_crlf) {
|
|
char c = *tbuff;
|
|
|
|
// End of line?
|
|
if ( handle_crlf ) {
|
|
if ( c == '\n' ) {
|
|
lwhite = 1; // restart leading white flag
|
|
} else {
|
|
// End of leading white? (used by #directive)
|
|
if ( !strchr(" \t", c) ) lwhite = 0;
|
|
}
|
|
}
|
|
|
|
// Adjust and advance
|
|
// If handling crlfs, zero col on crlf. If not handling, let col continue to count past crlf
|
|
// e.g. for multiline #define's that have lines ending in backslashes.
|
|
//
|
|
col = (c=='\n') ? (handle_crlf ? 0 : col) : col+1; // column counter
|
|
tbuff++; // advance text ptr
|
|
*sbuff++ = style; // apply style & advance its ptr
|
|
if ( --len <= 0 ) return 0; // keep track of length
|
|
return 1;
|
|
}
|
|
|
|
// Parse over white space using current style
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_over_white() {
|
|
while ( len > 0 && strchr(" \t", *tbuff))
|
|
{ if ( !parse_over_char() ) return 0; }
|
|
return 1;
|
|
}
|
|
|
|
// Parse over non-white alphabetic text
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_over_alpha() {
|
|
while ( len > 0 && isalpha(*tbuff) )
|
|
{ if ( !parse_over_char() ) return 0; }
|
|
return 1;
|
|
}
|
|
|
|
// Parse to end of line in specified style.
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_to_eol(char s) {
|
|
char save = style;
|
|
style = s;
|
|
while ( *tbuff != '\n' )
|
|
{ if ( !parse_over_char() ) return 0; }
|
|
style = save;
|
|
return 1;
|
|
}
|
|
|
|
// Parse a block comment until end of comment or buffer.
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_block_comment() {
|
|
char save = style;
|
|
style = 'C'; // block comment style
|
|
while ( len > 0 ) {
|
|
if ( strncmp(tbuff, "*/", 2) == 0 ) {
|
|
if ( !parse_over_char() ) return 0; // handle '*'
|
|
if ( !parse_over_char() ) return 0; // handle '/'
|
|
break;
|
|
}
|
|
if ( !parse_over_char() ) return 0; // handle comment text
|
|
}
|
|
style = save; // revert style
|
|
return 1;
|
|
}
|
|
|
|
// Copy keyword from tbuff -> keyword[] buffer
|
|
void StyleParse::buffer_keyword() {
|
|
char *key = keyword;
|
|
char *kend = key + sizeof(keyword) - 1; // end of buffer
|
|
for ( const char *s=tbuff;
|
|
(islower(*s) || *s=='_') && (key < kend);
|
|
*key++ = *s++ ) { }
|
|
*key = 0; // terminate
|
|
}
|
|
|
|
// Parse over specified 'key'word in specified style 's'.
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_over_key(const char *key, char s) {
|
|
char save = style;
|
|
style = s;
|
|
// Parse over the keyword while applying style to sbuff
|
|
while ( *key++ )
|
|
{ if ( !parse_over_char() ) return 0; }
|
|
last = 1;
|
|
style = save;
|
|
return 1;
|
|
}
|
|
|
|
// Parse over angle brackets <..> in specified style.
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_over_angles(char s) {
|
|
if ( *tbuff != '<' ) return 1; // not <..>, early exit
|
|
char save = style;
|
|
style = s;
|
|
// Parse over angle brackets in specified style
|
|
while ( len > 0 && *tbuff != '>' )
|
|
{ if ( !parse_over_char() ) return 0; } // parse over '<' and angle content
|
|
if ( !parse_over_char() ) return 0; // parse over trailing '>'
|
|
style = save;
|
|
return 1;
|
|
}
|
|
|
|
// Parse line for possible keyword
|
|
// spi.keyword[] will contain parsed word.
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_keyword() {
|
|
// Parse into 'keyword' buffer
|
|
buffer_keyword();
|
|
char *key = keyword;
|
|
// C/C++ type? (void, char..)
|
|
if ( search_types(key) )
|
|
return parse_over_key(key, 'F'); // 'type' style
|
|
// C/C++ Keyword? (switch, return..)
|
|
else if ( search_keywords(key) )
|
|
return parse_over_key(key, 'G'); // 'keyword' style
|
|
// Not a type or keyword? Parse over it
|
|
return parse_over_key(key, style);
|
|
}
|
|
|
|
// Style parse a quoted string, either "" or ''.
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_quoted_string(char quote_char, // e.g. '"' or '\''
|
|
char in_style) { // style for quoted text
|
|
style = in_style; // start string style
|
|
if ( !parse_over_char() ) return 0; // parse over opening quote
|
|
|
|
// Parse until closing quote reached
|
|
char c;
|
|
while ( len > 0 ) {
|
|
c = tbuff[0];
|
|
if ( c == quote_char ) { // Closing quote? Parse and done
|
|
if ( !parse_over_char() ) return 0; // close quote
|
|
break;
|
|
} else if ( c == '\\' ) { // Escape sequence? Parse over, continue
|
|
if ( !parse_over_char() ) return 0; // escape
|
|
if ( !parse_over_char() ) return 0; // char being escaped
|
|
continue;
|
|
}
|
|
// Keep parsing until end of buffer or closing quote..
|
|
if ( !parse_over_char() ) return 0;
|
|
}
|
|
style = 'A'; // revert normal style
|
|
return 1;
|
|
}
|
|
|
|
// Style parse a directive (#include, #define..)
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_directive() {
|
|
style = 'E'; // start directive style
|
|
if ( !parse_over_char() ) return 0; // Parse over '#'
|
|
if ( !parse_over_white() ) return 0; // Parse over any whitespace after '#'
|
|
if ( !parse_over_alpha() ) return 0; // Parse over the directive
|
|
style = 'A'; // revert normal style
|
|
if ( !parse_over_white() ) return 0; // Parse over white after directive
|
|
if ( !parse_over_angles('D')) return 0; // #include <..> (if any)
|
|
return 1;
|
|
}
|
|
|
|
// Style parse a line comment to end of line.
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_line_comment() {
|
|
return parse_to_eol('B');
|
|
}
|
|
|
|
// Parse a backslash escape character sequence.
|
|
// Purposefully don't 'handle' \n, since an escaped \n should be
|
|
// a continuation of a line, such as in a multiline #directive.
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_escape() {
|
|
const char no_crlf = 0;
|
|
if ( !parse_over_char(no_crlf) ) return 0; // backslash
|
|
if ( !parse_over_char(no_crlf) ) return 0; // char escaped
|
|
return 1;
|
|
}
|
|
|
|
// Parse all other non-specific characters
|
|
// Returns 0 if hit end of buffer, 1 otherwise.
|
|
//
|
|
int StyleParse::parse_all_else() {
|
|
last = isalnum(*tbuff) || *tbuff == '_' || *tbuff == '.';
|
|
return parse_over_char();
|
|
}
|