fltk/fluid/StyleParse.cxx
Matthias Melcher 16dae3ea06 Fluid: restructuring and commenting.
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.
2021-12-08 15:52:15 +01:00

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();
}