/
trilirium
/
Archived_BLC
Обзор
Документация
Войти
/
trilirium
/
Archived_BLC
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
parser.cpp
2 299 строк
55 KB
Trilirium
repo created OK
22 янв 2026, 16:43
22 янв 2026, 16:43
f05d14b
Код
Авторство
О чём код?
/* + === - === - === - === - === - === - === - === | | parser.cpp | | Parsing formatted text source content | + === - === - === - === - === - === - === - === */ // Character to upper case static char char_to_UC (char ch) { return 'a' <= ch && ch <= 'z' ? ch - 'a' + 'A' : ch; } // Character to lower case static char char_to_LC (char ch) { return 'A' <= ch && ch <= 'Z' ? ch + 'a' - 'A' : ch; } // Check for slash character: static bool cp_slash (char ch) { return ch == '\\'; } // cp_slash // Check for hash: static bool cp_hash (char ch) { return ch == '#'; } // cp_hash // Check for comma: static bool cp_comma (char ch) { return ch == ','; } // cp_comma // Check for colon: static bool cp_colon (char ch) { return ch == ':'; } // cp_colon // Check for identifier character: static bool cp_ident (char ch) { return ('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || ('0' <= ch && ch <= '9') || (ch == '#') // (comment) || (ch == '_') // (non-break space) || (ch == '$') // (user style apply) || (ch == '*') // (paragraph) ; } // cp_ident // Check for blank character: static bool cp_space (char ch) { return (ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\r'); } // cp_space // Check for break character: static bool cp_break (char ch) { return (ch == '\n'); } // cp_break // Check for flag character: static bool cp_bool (char ch) { return ch == '+' || ch == '-' || ch == '~'; } // cp_bool // Skip from 'ptr' (while is 'ch'). // Return 0, if EOL reached static char const *skip_while (char const *ptr, char ch) { while (*ptr && *ptr == ch) ++ ptr; return *ptr ? ptr : 0; } // skip_while // Skip from 'ptr' (while is NOT 'ch'). // Return 0, if EOL reached static char const *skip_until (char const *ptr, char ch) { while (*ptr && *ptr != ch) ++ ptr; return *ptr ? ptr : 0; } // skip_until // Skip {start..end} inclusive (for 'cp_pred'). static char const *skip_check_in (char const *start, char const *end, bool (*cp_pred) (char ch)) { while (start != end && cp_pred (*start)) ++ start; return start; } // skip_check_in // Skip {start..end} exclusive (for 'cp_pred'). static char const *skip_check_ex (char const *start, char const *end, bool (*cp_pred) (char ch)) { while (start != end && !cp_pred (*start)) ++ start; return start; } // skip_check_ex // Wide string length unsigned w_length (wchar_t *w_text) { unsigned length = 0; while (*w_text ++) length ++; return length; } // w_length // Check for 'pure' ASCII content (start [length]) bool is_ASCII_pure (char const *start, unsigned length) { while (length --) if (*start ++ & 0x80) return false; return true; } // is_ASCII_pure #include "mem_mgr.h" #include "canvas.h" #include "textform.h" // // Parser modes // enum Parse_Mode { Parse_Plain = 0, // unformatted (not split source) Parse_Words = 1, // split source in words Parse_Lines = 2, // split source in lines Parse_Coords = 3 // points/vertices list }; // Parse_Mode // // Actual parser class // class Parser { unsigned short parse_mode; unsigned short parse_depth; unsigned short attr_depth; char const *parse_start; TFE_Term ** tail_link; public: unsigned short error_count; // (optional) decoder wchar_t * (* decoder) (char const *source, unsigned len); // (error handler) void (* error_handler) (char const *message, unsigned offset, unsigned length); // (constructor) Parser (TFE_Term * &tail) { tail_link = &tail; attr_depth = parse_mode = parse_depth = 0; decoder = 0; parse_start = 0; error_handler = 0; error_count = 0; }; // Parser // (handle parse error) char const * parse_error (char const *source_ptr, int source_len, char const *message) { if (error_handler && parse_start) { if (source_len < 0) { source_len = - source_len; source_ptr -= source_len; } (* error_handler) (message, source_ptr - parse_start, source_len); } ++ error_count; return source_ptr; } // parse_error // Append node to chain void append_node (TFE_Term *node) { TFE_Term *prev = *tail_link; *tail_link = node; while (* (tail_link = &node->next)) node = *tail_link; *tail_link = prev; } // append_node // Appending: character void append_char (char ch) { append_node (new ("Text:char") TFE_Char (ch)); } // append_char // Set word parse mode: void word_parse (bool word) { parse_mode = word ? Parse_Words : Parse_Plain; } // Attribute definitions static struct character_def character_tab []; // Predeclare: parse character ... static unsigned parse_character (char const *c_start, char const *c_end); // Predeclare: parse vertex ... static bool parse_vertex (char const *t_start, char const *t_end, Point &point); // Appending: text fragment void append_text_frag (char const *f_start, char const *f_end) { if (decoder && ! is_ASCII_pure (f_start, f_end - f_start)) { // (apply decoder to source) wchar_t *result = (* decoder) (f_start, f_end - f_start); if (result) { append_node (new ("Text:U_word") TFE_W_Text_C (w_length (result), result)); delete result; } } else append_node (new ("Text:word") TFE_Text_C (f_end - f_start, f_start)); } // append_text_frag // Appending: character list void parse_character_list (char const *t_start, char const *t_end) { if (t_start < t_end) { enum { W_Limit = 64 }; unsigned W_count = 0; wchar_t W_text [W_Limit]; char const *num_beg; while ((num_beg = skip_check_in (t_start, t_end, cp_space)) < t_end && W_count != W_Limit) { char const *num_end = skip_check_ex (num_beg, t_end, cp_space); char const *num_colon = skip_check_ex (num_beg, num_end, cp_colon); t_start = num_end; if (num_beg < num_colon && num_colon + 1 < num_end) { // (parse character range) unsigned start_range = parse_character (num_beg, num_colon); unsigned end_range = parse_character (num_colon + 1, num_end); while (start_range <= end_range && W_count != W_Limit) W_text [W_count ++] = start_range ++; } else { // (parse single character) unsigned value = parse_character (num_beg, num_end); W_text [W_count ++] = value; } } // while if (W_count == 1) append_node (new ("Text:wide_char") TFE_W_Char (*W_text)); else append_node (new ("Text:wide_list") TFE_W_Text_C (W_count, W_text)); // (something remains?) if (t_start < t_end) parse_character_list (t_start, t_end); } } // parse_character_list // Check for inner def / advance char const * inner_closure (char C_open, char C_close, char const *i_start, char const *t_end, void (Parser::* action) (char const *c_start, char const *c_end)) { if (*i_start == C_open) { char const *i_end = i_start + 1; while (i_end != t_end && *i_end != C_close) ++ i_end; if (i_end != t_end) { // (found!) (this->*action) (i_start + 1, i_end); return ++ i_end; } } // (not found!) return 0; } // inner_closure // Appending: vertex coordinates list... unsigned parse_points_list (char const *t_start, char const *t_end) { Point initial (0, 0); unsigned count = 0; if (t_start < t_end) { char const *v_beg, *v_end; while ((v_beg = skip_check_in (t_start, t_end, cp_space)) < t_end) { // char literal sequence ? if (v_end = inner_closure ('[', ']', v_beg, t_end, &Parser::append_text_frag)); // OR: codes list ? else if (v_end = inner_closure ('<', '>', v_beg, t_end, &Parser::parse_character_list)); // OR: single vertex ? else if (parse_vertex (v_beg, v_end = skip_check_ex (v_beg, t_end, cp_space), initial)) append_node (new ("Text:vertex") TFE_Vertex (initial)); t_start = v_end; } // while (v_beg < t_end) } } // parse_points_list // Open attribute void open_attr (TFE_Attr *attr) { attr->next = *tail_link; *tail_link = attr; TFE_Attr *start = attr; while (attr && *(tail_link = &attr->list)) attr = (*tail_link)->as_Attr (); *tail_link = start; ++ attr_depth; } // open_attr // Close attribute void close_attr () { TFE_Term *attr = *tail_link; *tail_link = 0; tail_link = &attr->next; -- attr_depth; } // close_attr // Appending: text node void append_text (char const *t_start, char const *t_end) { if (t_start < t_end) switch (parse_mode) { case Parse_Coords: parse_points_list (t_start, t_end); break; case Parse_Lines: { char const *t_div; // (temporary set mode) parse_mode = Parse_Words; // (split text into lines) while ((t_div = skip_check_in (t_start, t_end, cp_break)) < t_end) { // (another line to add:) t_start = skip_check_ex (t_div, t_end, cp_break); open_attr (new ("Para_Line") TFE_A_Para ()); append_text (t_div, t_start); // (recurse!) close_attr (); } // while // (restore mode) parse_mode = Parse_Lines; } break; case Parse_Words: { char const *t_div; // (split text into words) while ((t_div = skip_check_in (t_start, t_end, cp_space)) < t_end) { // (another word to add:) t_start = skip_check_ex (t_div, t_end, cp_space); append_text_frag (t_div, t_start); } // while } break; default: // (single plain node) append_text_frag (t_start, t_end); } // switch } // append_text // Check for initial glue: bool glue_init (char const *t_at) { if (*t_at && ! cp_space (*t_at)) { append_node (new ("Text:glue") TFE_WordGlue ()); return true; } return false; } // glue_init // Check for terminal glue: bool glue_term (char const *t_start, char const *t_end) { if (t_start < t_end && ! cp_space (t_end [-1])) { append_node (new ("Text:glue") TFE_WordGlue ()); return true; } return false; } // glue_term TFE_Attr *attr_lookup (char const *attr_name, char const *attr_arg, char const *attr_end); // Parse attribute TFE_Attr * parse_attr (char const *a_start, char const *a_end) { if (a_start < a_end) { char const *a_div = skip_check_in (a_start, a_end, cp_ident); char const *a_next = skip_check_ex (a_div, a_end, cp_slash); if (a_div > a_start) { if (a_next < a_end) { TFE_Attr *attr = attr_lookup (a_start, a_div, a_next); attr->list = parse_attr (a_next + 1, a_end); return attr; } else return attr_lookup (a_start, a_div, a_end); } // (not-empty attribute) } // (not-empty context) // (empty??) return new ("Attr::") TFE_Attr (); } // parse_attr // Parse user style definition void parse_user_style (char const *u_start, char const *u_end); // // Parser main entry point // (recursive!) // char const *parse_source (char const *start_ptr) { char const *end_ptr = start_ptr; char ch; if (! parse_depth) { parse_start = start_ptr; } while (ch = *end_ptr ++) { if (ch == '\\') { append_text (start_ptr, end_ptr - 1); switch (*end_ptr) { // (handle '\0'?) case '\\': case '{': case '}': // (literals) append_char (*end_ptr ++); start_ptr = end_ptr; break; case '|': // (force line break:) start_ptr = end_ptr + 1; append_node (new ("ParaBreak") TFE_ParaBreak ()); break; case '+': // (force words glue:) start_ptr = end_ptr + 1; append_node (new ("WordGlue") TFE_WordGlue ()); break; case '^': // (force words nail:) start_ptr = end_ptr + 1; append_node (new ("WordNail") TFE_WordNail ()); break; case '_': // (non-break space!) start_ptr = end_ptr + 1; append_char (0xA0); break; case '[': // (literal sequence) glue_term (start_ptr, end_ptr - 1); start_ptr = end_ptr; if (end_ptr = skip_until (start_ptr, ']')) { append_text (start_ptr + 1, end_ptr); start_ptr = end_ptr + 1; glue_init (start_ptr); break; } else return parse_error (start_ptr - 1, 2, "no closing ']'"); case '<': // (encoded sequence) glue_term (start_ptr, end_ptr - 1); start_ptr = end_ptr; if (end_ptr = skip_until (start_ptr, '>')) { parse_character_list (start_ptr + 1, end_ptr); start_ptr = end_ptr + 1; glue_init (start_ptr); break; } else return parse_error (start_ptr - 1, 2, "no closing '>'"); case '%': // (user style def) start_ptr = end_ptr; if (end_ptr = skip_until (++ start_ptr, '%')) { parse_user_style (start_ptr, end_ptr); start_ptr = end_ptr + 1; break; } else return parse_error (start_ptr - 1, 2, "no closing '%'"); default: // (apply attribute to block) glue_term (start_ptr, end_ptr - 1); start_ptr = end_ptr; if (end_ptr = skip_until (start_ptr, '{')) { unsigned short prev_mode = parse_mode; ++ parse_depth; open_attr (parse_attr (start_ptr, end_ptr)); end_ptr = parse_source (end_ptr + 1); close_attr (); -- parse_depth; // (unclosed bracket?) if (! end_ptr) return 0; parse_mode = prev_mode; start_ptr = end_ptr; glue_init (start_ptr); break; } else return parse_error (start_ptr - 1, 2, "opening '{'"); } // switch } // (escape) else if (ch == '{') { // (block without attribute) append_text (start_ptr, end_ptr - 1); glue_term (start_ptr, end_ptr - 1); ++ parse_depth; start_ptr = end_ptr = parse_source (end_ptr); -- parse_depth; // (unclosed bracket?) if (! start_ptr) return 0; glue_init (start_ptr); } else if (ch == '}') { if (parse_depth) { // (add final node!) append_text (start_ptr, end_ptr - 1); return end_ptr; } else { parse_error (end_ptr - 1, 1, "close without open!"); start_ptr = end_ptr; } } } // while (ch) // (final fragment) append_text (start_ptr, end_ptr - 1); if (parse_depth) { parse_error (end_ptr, 0, "not all blocks are closed!"); return 0; } else parse_start = 0; return end_ptr; } // parse_source // Collect nodes in paragraph static void para_wrap (TFE_Term *&chain); }; // Parser // // Paragraph wrapping // (Collect free nodes in paragraph) // // (predicate to check) #if 0 static bool check_para (TFE_Term *p_node) { return (dynamic_cast <TFE_A_Para *> (p_node) != 0) || (dynamic_cast <TFE_A_ParaLines *> (p_node) != 0) || (dynamic_cast <TFE_A_Form *> (p_node) != 0); } // check_para #endif static bool check_para (TFE_Term *p_node) { return p_node && (p_node->as_Para () != 0); } // check_para // Paragraph wrapping: // apply paragraph wraps void Parser::para_wrap (TFE_Term * &chain) { TFE_Term *p_node; TFE_A_Para *p_para = 0; // (active paragraph) for (TFE_Term **p_term = &chain; p_node = *p_term; p_term = &p_node->next) { if (check_para (p_node)) { // (paragraph node) if (p_para) { // (close paragraph) *p_term = 0; p_para->next = p_node; p_para = 0; } } else { // (default node) if (! p_para) { // (open paragraph) p_para = new ("Para/Wrapped") TFE_A_Para (); *p_term = p_para; // (insert) p_para->list = p_node; p_para->next = 0; } } } // for () } // Parser::para_wrap // // String cache // class S_Cache { const char *name; unsigned capacity; struct S_Node { char const *value; S_Node *next; } ** storage; // (hash for string) static unsigned hcode (char const *src, unsigned len) { unsigned _hash = 0; while (len --) { _hash ^= ((unsigned) * src ++ * 17); _hash <<= 2; } return _hash & 0xFFFF; } // hcode public: // constructor S_Cache (const char *name, unsigned capacity) { this->name = name; this->capacity = capacity; storage = new (name) S_Node * [capacity]; for (int i = 0; i != capacity; ++ i) storage [i] = 0; } // S_Cache // destructor ~S_Cache () { // TBD: remove all delete [] storage; } // (insert new string) char const * insert (char const *str, unsigned len) { S_Node * &start = storage [capacity > 1 ? hcode (str, len) % capacity : 0]; for (S_Node *node = start; node; node = node->next) if (strlen (node->value) == len && memcmp (str, node->value, len) == 0) return node->value; // (found!) // (copy string) char *_value = new (name) char [len + 1]; memcpy (_value, str, len); _value [len] = '\0'; // (add new node to chain) S_Node *fresh = new (name) S_Node; fresh->value = _value; fresh->next = start; start = fresh; return _value; } // insert // (release all entries) void release () { // (free nodes) for (unsigned i = 0; i != capacity; ++ i) { S_Node *entry = storage[i]; while (entry) { S_Node *next = entry->next; delete entry->value; delete entry; entry = next; } // while () } // (free storage vector) delete [] storage; storage = 0; } // release }; // S_Cache // Font names cache static S_Cache font_cache ("_fonts_", 8); // Style names cache static S_Cache style_cache ("_styles_", 4); #include "parser.h" // Copy context as string char const *Prime_Parser::copy_text (char const *_tag) { if (arg_beg < arg_end) { unsigned length = arg_end - arg_beg; char *buffer = new (_tag) char [length + 1]; memcpy (buffer, arg_beg, length); buffer [length] = '\0'; return buffer; } return 0; } // Prime_Parser::copy_text // // Trim extra spaces // (at start of {arg_beg .. arg_end}.) // void Prime_Parser::trim_beg () { char const * _src_beg = arg_beg; while (_src_beg != arg_end && cp_space (* _src_beg)) ++ _src_beg; arg_beg = _src_beg; } // Prime_Parser::trim_beg // // Trim extra spaces // (at end of {arg_beg .. arg_end}.) // void Prime_Parser::trim_end () { char const * _src_end = arg_end; while (arg_beg != _src_end && cp_space (_src_end[-1])) -- _src_end; arg_end = _src_end; } // Prime_Parser::trim_end // Parse unsigned decimal value <- {arg_ptr .. arg_end} unsigned Prime_Parser::parse_decimal () { trim_beg (); char const *arg_ptr = arg_beg; unsigned value = 0; for (char ch; arg_ptr != arg_end && (ch = *arg_ptr); ++ arg_ptr) { if ('0' <= ch && ch <= '9') value = value * 10 + (ch - '0'); else if (ch != '_') break; } // for (arg_ptr) arg_beg = arg_ptr; return value; } // Prime_Parser::parse_decimal // Parse unsigned octal value <- {arg_ptr .. arg_end} unsigned Prime_Parser::parse_octal () { char const *arg_ptr = arg_beg; trim_beg (); unsigned value = 0; for (char ch; arg_ptr != arg_end && (ch = *arg_ptr); ++ arg_ptr) { if ('0' <= ch && ch <= '7') value = (value << 3) + (ch - '0'); else if (ch != '_') break; } // for (arg_ptr) arg_beg = arg_ptr; return value; } // Prime_Parser::parse_octal // Parse unsigned hex value <- {arg_ptr .. arg_end} unsigned Prime_Parser::parse_hex () { char const *arg_ptr = arg_beg; trim_beg (); unsigned value = 0; for (char ch; arg_ptr != arg_end && (ch = *arg_ptr); ++ arg_ptr) { if ('0' <= ch && ch <= '9') value = (value << 4) + (ch - '0'); else if ('A' <= ch && ch <= 'F') value = (value << 4) + (ch - 'A' + 10); else if ('a' <= ch && ch <= 'f') value = (value << 4) + (ch - 'a' + 10); else if (ch != '_') break; } // for (arg_ptr) arg_beg = arg_ptr; return value; } // Prime_Parser::parse_hex // Trim (optional) quotes // (at start/end of {start..end}). void Prime_Parser::un_quote () { char ch; if (arg_end - arg_beg >= 2 && (ch = * arg_beg) == arg_end [-1] && (ch == '"' || ch == '\'') ) { ++ arg_beg; -- arg_end; } } // Prime_Parser::un_quote // Parse length (distance) value <- {arg_ptr .. arg_end} unsigned Prime_Parser::parse_length () { trim_beg (); trim_end (); if (arg_end > arg_beg) { if (*arg_beg == '[') ++ arg_beg; if (arg_end[-1] == ']') -- arg_end; return parse_decimal (); } else { arg_error ("length"); return 0; } } // Prime_Parser::parse_length // Parse font size/width value <- {arg_ptr .. arg_end} unsigned Prime_Parser::parse_size () { trim_end (); if (arg_end > arg_beg) return parse_decimal (); else { arg_error ("size"); return 0; } } // Prime_Parser::parse_size // Parse font name <- {arg_ptr .. arg_end} char const * Prime_Parser::parse_font_name () { trim_beg (); trim_end (); un_quote (); unsigned arg_len = arg_end - arg_beg; if (arg_len) return font_cache.insert (arg_beg, arg_len); arg_error ("font_name"); return ""; } // Prime_Parser::parse_font_name // Parse user style name <- {arg_ptr .. arg_end} char const * Prime_Parser::parse_style_name () { trim_beg (); trim_end (); arg_end = skip_check_in (arg_beg, arg_end, cp_ident); unsigned arg_len = arg_end - arg_beg; if (arg_len) return style_cache.insert (arg_beg, arg_len); arg_error ("style_name"); return 0; // (no name) } // Prime_Parser::parse_style_name // Parse color value <- {arg_ptr .. arg_end} Color Prime_Parser::parse_color () { Color result; trim_beg (); trim_end (); if (arg_beg < arg_end) switch (*arg_beg ++) { case '#': // (hex: RrGgBb) result = parse_hex (); result = ((result & 0xFF) << 16) | (result & 0xFF00) | ((result & 0xFF0000) >> 16); return result; case '%': // (hex: RGB) result = parse_hex (); result = 0x11 * (((result & 0xF) << 16) | ((result & 0xF0) << 4) | ((result & 0xF00) >> 8)); return result; case 'K': case 'k': // (Black) result = 0; break; case 'R': case 'r': // (Red) result = C_Red (0xFF); break; case 'G': case 'g': // (Green) result = C_Green (0xFF); break; case 'B': case 'b': // (Blue) result = C_Blue (0xFF); break; case 'C': case 'c': // (Cyan) result = C_Cyan (0xFF); break; case 'M': case 'm': // (Magenta) result = C_Magenta (0xFF); break; case 'Y': case 'y': // (Yellow) result = C_Yellow (0xFF); break; case 'W': case 'w': // (Grey) result = C_Grey (0xFF); break; default: return ~0; } // switch else { arg_error ("color"); return 0; // (no name) } if (arg_beg < arg_end && *arg_beg ++ == '#') { // (color intensity) unsigned intensity = parse_hex () & 0xFF; result = (result / 0xFF) * intensity; } return result; } // Prime_Parser::parse_color // Parse alignment mode (vertical/horizontal) int Prime_Parser::parse_align () { trim_beg (); trim_end (); if (arg_beg != arg_end) switch (*arg_beg) { // (align left / top) case '-': case '<': case 'L': case 'l': case 'T': case 't': return -1; // (align right / bottom) case '+': case '>': case 'R': case 'r': case 'B': case 'b': return 1; // (align center) case '=': case 'C': case 'c': return 0; // (align full == justify) case '*': case 'J': case 'j': return 2; } arg_error ("align"); return 0; // ????? } // Prime_Parser::parse_align // Parse: vertex coordinate (possibly, incremental)... void Prime_Parser::parse_vertex_coord (int &coord) { if (arg_beg < arg_end) { int sign; switch (*arg_beg) { case '+': // (add to preceding) sign = 1; ++ arg_beg; break; case '-': // (subtract from preceding) sign = -1; ++ arg_beg; break; default: sign = 0; } // switch int value = parse_decimal (); if (sign > 0) { value ? (coord += value) : ++ coord; -- arg_beg; } else if (sign < 0) { value ? (coord -= value) : -- coord; -- arg_beg; } else coord = value; } // (not empty) } // Prime_Parser::parse_vertex_coord // Parse: single vertex ... bool Prime_Parser::parse_vertex (Point &point) { char const *vertex_div = skip_check_ex (arg_beg, arg_end, cp_colon); if (vertex_div < arg_end) { char const *_arg_beg = arg_beg, *_arg_end = arg_end; arg_end = vertex_div; parse_vertex_coord (point.X); arg_end = _arg_end; arg_beg = vertex_div + 1; parse_vertex_coord (point.Y); arg_beg = _arg_beg; return true; } // (valid vertex) // (no valid vertex!) arg_error ("vertex"); return false; } // Prime_Parser::parse_vertex // Parse Point value <- {arg_ptr .. arg_end} Point Prime_Parser::parse_point () { if (arg_beg && arg_end) { trim_beg (); trim_end (); if (*arg_beg == '[') ++ arg_beg; if (arg_end[-1] == ']') -- arg_end; char const *arg_div = skip_check_ex (arg_beg, arg_end, cp_comma); if (arg_div < arg_end) { char const *_arg_beg = arg_beg, *_arg_end = arg_end; unsigned X, Y; arg_end = arg_div; X = parse_decimal (); arg_end = _arg_end; arg_beg = arg_div + 1; Y = parse_decimal (); arg_beg = _arg_beg; return Point (X, Y); } } return Point (0, 0); } // Prime_Parser::parse_point // Parse Rect value <- {arg_ptr .. arg_end} Rect Prime_Parser::parse_rect () { if (arg_beg && arg_end) { trim_beg (); trim_end (); char const *arg_div = skip_check_ex (arg_beg, arg_end, cp_colon); if (arg_div < arg_end) { char const *_arg_beg = arg_beg, *_arg_end = arg_end; Point LT, RB; arg_end = arg_div; LT = parse_point (); arg_end = _arg_end; arg_beg = arg_div + 1; RB = parse_point (); arg_beg = _arg_beg; return Rect (LT, RB); } } return Rect (0, 0, 0, 0); } // Prime_Parser::parse_rect // Parse Area value <- {arg_ptr .. arg_end} Area Prime_Parser::parse_area () { if (arg_beg && arg_end) { trim_beg (); trim_end (); char const *arg_div = skip_check_ex (arg_beg, arg_end, cp_hash); if (arg_div < arg_end) { char const *_arg_beg = arg_beg, *_arg_end = arg_end; Point Origin (0, 0), Extent (0, 0); arg_end = arg_div; Origin = parse_point (); arg_end = _arg_end; arg_beg = arg_div + 1; Extent = parse_point (); arg_beg = _arg_beg; Extent.shift (Origin); return Area (Origin, Extent); } } return Area (0, 0, 0, 0); } // Prime_Parser::parse_area // Parse boolean (flag) value <- {arg_ptr .. arg_end} bool Prime_Parser::parse_flag () { trim_beg (); if (arg_beg != arg_end) switch (* arg_beg) { case '+': return true; case '-': return false; case '~': return false; default: arg_error ("boolean"); } return true; } // Prime_Parser::parse_flag // Parse resource <- {arg_ptr .. arg_end} char * Prime_Parser::parse_RL (char const *_tag) { if (arg_beg && arg_end) { // (allow initial ':') if (*arg_beg == ':') ++ arg_beg; trim_beg (); trim_end (); if (arg_beg != arg_end) { unsigned arg_len = arg_end - arg_beg; char *_RL = new (_tag) char [arg_len + 1]; _RL [arg_len] = '\0'; memcpy (_RL, arg_beg, arg_len); return _RL; } } // (arg_beg && arg_end) arg_error ("IRL|URL"); return 0; // (empty) } // Prime_Parser::parse_RL // // Actual attribute constructors... // struct Arg_Parser : Prime_Parser { unsigned short &attr_mode; // // Constructor // Arg_Parser (char const *arg_beg, char const *arg_end, unsigned short &attr_mode) : Prime_Parser (arg_beg, arg_end), attr_mode (attr_mode) {} // // Argument constructors // // (parse span ID) char * parse_spanID (char const *_tag, bool &asterisk) { if (arg_beg && arg_end) { trim_beg (); trim_end (); if (arg_beg != arg_end) { unsigned arg_len = arg_end - arg_beg; if (*arg_beg == '*') { asterisk = true; ++ arg_beg; -- arg_len; } else { asterisk = false; } char *_ID = new (_tag) char [arg_len + 1]; _ID [arg_len] = '\0'; memcpy (_ID, arg_beg, arg_len); return _ID; } } // (arg_beg && arg_end) arg_error ("span ID"); return 0; // (empty) } // parse_spanID // (form wrapper) TFE_Attr *parse_Form () { return new ("Attr:Form") TFE_A_Form (parse_length ()); } // (paragraph wrapper) TFE_Attr *parse_Para () { attr_mode = Parse_Words; return new ("Attr:Para") TFE_A_Para (); } // (style bold) TFE_Attr *parse_Bold () { return new ("Attr:Bold") TFE_A_Bold (parse_flag ()); } // (style italic) TFE_Attr *parse_Italic () { return new ("Attr:Italic") TFE_A_Italic (parse_flag ()); } // (style underline) TFE_Attr *parse_ULine () { return new ("Attr:ULine") TFE_A_ULine (parse_flag ()); } // (style overstrike) TFE_Attr *parse_OStrike () { return new ("Attr:OStrike") TFE_A_OStrike (parse_flag ()); } // (set font face) TFE_Attr *parse_FontFace () { return new ("Attr:FontFace") TFE_A_FontFace (parse_font_name ()); } // (set font size) TFE_Attr *parse_FontSize () { return new ("Attr:FontSize") TFE_A_FontSize (parse_size ()); } // (set font width) TFE_Attr *parse_FontWidth () { return new ("Attr:FontWidth") TFE_A_FontWidth (parse_size ()); } // (set font color) TFE_Attr *parse_FontColor () { return new ("Attr:FontColor") TFE_A_FontColor (parse_color ()); } // (set font background color) TFE_Attr *parse_BackColor () { return new ("Attr:FontBack") TFE_A_BackColor (parse_color ()); } // (set font effects) TFE_Attr *parse_FontEffect () { return new ("Attr:FontEffect") TFE_A_FontEffect (); } // (set paragraph horizontal align) TFE_Attr *parse_ParaHorAlign () { return new ("Attr:ParHorAlign") TFE_A_ParaHorAlign (parse_align ()); } // (set paragraph vertical align) TFE_Attr *parse_ParaVerAlign () { return new ("Attr:ParVerAlign") TFE_A_ParaVerAlign (parse_align ()); } // (set paragraph word space) TFE_Attr *parse_ParaWSpace () { return new ("Attr:ParSpace") TFE_A_ParaSpace (parse_length ()); } // (set paragraph left indent) TFE_Attr *parse_ParaLeft () { return new ("Attr:ParLeft") TFE_A_ParaLeft (parse_length ()); } // (set paragraph right indent) TFE_Attr *parse_ParaRight () { return new ("Attr:ParRight") TFE_A_ParaRight (parse_length ()); } // (set paragraph first indent) TFE_Attr *parse_ParaFirst () { return new ("Attr:ParFirst") TFE_A_ParaFirst (parse_length ()); } // (set paragraph space above) TFE_Attr *parse_ParaAbove () { return new ("Attr:ParaAbove") TFE_A_ParaAbove (parse_length ()); } // (set paragraph space below) TFE_Attr *parse_ParaBelow () { return new ("Attr:ParaBelow") TFE_A_ParaBelow (parse_length ()); } // (set paragraph space between lines) TFE_Attr *parse_ParaInter () { return new ("Attr:ParaInter") TFE_A_ParaInter (parse_length ()); } // (lines splitter) TFE_Attr *parse_ParaLines () { attr_mode = Parse_Lines; return new ("Attr:ParaLines") TFE_A_ParaLines (); } TFE_Attr *parse_TextSpan (bool state) { bool ignored; // (asterisk mark ignored) return new ("Attr:Span") TFE_TextSpan (parse_spanID ("_TextSpan", ignored), state); } // parse_TextSpan // (parse flagged span) TFE_Attr *parse_Span () { return parse_TextSpan (parse_flag ()); } // parse_Span // (parse opened span) TFE_Attr *parse_Show () { return parse_TextSpan (true); } // parse_Show // (parse closed span) TFE_Attr *parse_Hide () { return parse_TextSpan (false); } // parse_Hide // (links) TFE_Attr *parse_ALink () { return new ("Attr::ALink") TFE_A_Action (); } // (parse IRL action) TFE_Attr *parse_IRL () { return new ("Attr:Action/IRL") TFE_Action_IRL (0, parse_RL ("_IRL")); } // (parse URL action) TFE_Attr *parse_URL () { return new ("Attr:Action/URL") TFE_Action_URL (0, parse_RL ("_URL")); } // (parse span toggle) TFE_Attr *parse_Toggle () { bool toggle_attr; char *span_ID = parse_spanID ("span_toggle", toggle_attr); return new ("Attr:Action/Toggle") TFE_Action_Toggle (toggle_attr, 0, span_ID); } // parse_Toggle // // Graphic primitives // // (canvas object) TFE_Attr *parse_Canvas () { // TODO: parse color ... return new ("Attr:Canvas") TFE_Canvas (0x707070, parse_point ()); } // (list of points) TFE_Attr *parse_Points () { attr_mode = Parse_Coords; return new ("Attr:Points") TFE_G_Points (); } // (list of lines/vectors) TFE_Attr *parse_Lines () { attr_mode = Parse_Coords; return new ("Attr:Lines") TFE_G_Lines (); } // (list of rectangles) TFE_Attr *parse_Rects () { attr_mode = Parse_Coords; return new ("Attr:Rects") TFE_G_Rects (); } // (list of ellipses/ovals) TFE_Attr *parse_Ovals () { attr_mode = Parse_Coords; return new ("Attr:Ovals") TFE_G_Ovals (); } // (list of round rectangles) TFE_Attr *parse_RoundRects () { attr_mode = Parse_Coords; return new ("Attr:RoundRects") TFE_G_RoundRects (); } // (list of chords) TFE_Attr *parse_Chords () { attr_mode = Parse_Coords; return new ("Attr:Chords") TFE_G_Arcs (A_Canvas::ArcChord); } // (list of wedges) TFE_Attr *parse_Wedges () { attr_mode = Parse_Coords; return new ("Attr:Wedges") TFE_G_Arcs (A_Canvas::ArcWedge); } // (list of arcs) TFE_Attr *parse_Arcs () { attr_mode = Parse_Coords; return new ("Attr:Arcs") TFE_G_Arcs (A_Canvas::ArcPlain); } // (list of trigons) TFE_Attr *parse_Trigons () { attr_mode = Parse_Coords; return new ("Attr:Trigons") TFE_G_Trigons (); } // (list of text items) TFE_Attr *parse_GText () { attr_mode = Parse_Coords; return new ("Attr:GText") TFE_G_Text (); } // (set plot color) TFE_Attr *parse_PlotColor () { return new ("Attr:PlotColor") TFE_A_PlotColor (parse_color ()); } // (set fill color) TFE_Attr *parse_FillColor () { return new ("Attr:FillColor") TFE_A_FillColor (parse_color ()); } // (set both colors) TFE_Attr *parse_DrawColor () { return new ("Attr:DrawColor") TFE_A_PlotFillColor (parse_color ()); } // // Arguments table // static struct Arg_Def { char const *name_attr; TFE_Attr * (Arg_Parser::* parse_attr) (); } Arg_Table []; }; // Arg_Parser Arg_Parser::Arg_Def Arg_Parser::Arg_Table [] = { // (font attributes) { "b", &Arg_Parser::parse_Bold }, { "Bold", &Arg_Parser::parse_Bold }, { "i", &Arg_Parser::parse_Italic }, { "Italic", &Arg_Parser::parse_Italic }, { "u", &Arg_Parser::parse_ULine }, { "Underline", &Arg_Parser::parse_ULine }, { "s", &Arg_Parser::parse_OStrike }, { "Overstrike", &Arg_Parser::parse_OStrike }, { "FF", &Arg_Parser::parse_FontFace }, { "FontFace", &Arg_Parser::parse_FontFace }, { "FS", &Arg_Parser::parse_FontSize }, { "FontSize", &Arg_Parser::parse_FontSize }, { "FW", &Arg_Parser::parse_FontWidth }, { "FontWidth", &Arg_Parser::parse_FontWidth }, { "FC", &Arg_Parser::parse_FontColor }, { "FontColor", &Arg_Parser::parse_FontColor }, { "FB", &Arg_Parser::parse_BackColor }, { "FontBack", &Arg_Parser::parse_BackColor }, { "FX", &Arg_Parser::parse_FontEffect }, { "FontExt", &Arg_Parser::parse_FontEffect }, // (paragraph attributes) { "ParHorAlign", &Arg_Parser::parse_ParaHorAlign }, { "PHA", &Arg_Parser::parse_ParaHorAlign }, { "ParVerAlign", &Arg_Parser::parse_ParaVerAlign }, { "PVA", &Arg_Parser::parse_ParaVerAlign }, { "ParSpace", &Arg_Parser::parse_ParaWSpace }, { "PS", &Arg_Parser::parse_ParaWSpace }, { "ParLeft", &Arg_Parser::parse_ParaLeft }, { "PL", &Arg_Parser::parse_ParaLeft }, { "ParRight", &Arg_Parser::parse_ParaRight }, { "PR", &Arg_Parser::parse_ParaRight }, { "ParFirst", &Arg_Parser::parse_ParaFirst }, { "PF", &Arg_Parser::parse_ParaFirst }, { "ParInter", &Arg_Parser::parse_ParaInter }, { "PI", &Arg_Parser::parse_ParaInter }, { "ParAbove", &Arg_Parser::parse_ParaAbove }, { "PA", &Arg_Parser::parse_ParaAbove }, { "ParBelow", &Arg_Parser::parse_ParaBelow }, { "PB", &Arg_Parser::parse_ParaBelow }, // (paragraphs / containers) { "Form", &Arg_Parser::parse_Form }, { "Canvas", &Arg_Parser::parse_Canvas }, { "*", &Arg_Parser::parse_Para }, { "p", &Arg_Parser::parse_Para }, { "Para", &Arg_Parser::parse_Para }, { "**", &Arg_Parser::parse_ParaLines }, { "PP", &Arg_Parser::parse_ParaLines }, { "pp", &Arg_Parser::parse_ParaLines }, // (text spans) { "Span", &Arg_Parser::parse_Span }, { "Show", &Arg_Parser::parse_Show }, { "Hide", &Arg_Parser::parse_Hide }, // (actions / links) { "ALink", &Arg_Parser::parse_ALink }, { "IRL", &Arg_Parser::parse_IRL }, { "URL", &Arg_Parser::parse_URL }, { "Toggle", &Arg_Parser::parse_Toggle }, // (graphic objects) { "GPoints", &Arg_Parser::parse_Points }, { "GP", &Arg_Parser::parse_Points }, { "GLines", &Arg_Parser::parse_Lines }, { "GL", &Arg_Parser::parse_Lines }, { "GRects", &Arg_Parser::parse_Rects }, { "GR", &Arg_Parser::parse_Rects }, { "GOvals", &Arg_Parser::parse_Ovals }, { "GO", &Arg_Parser::parse_Ovals }, { "GRoundRects", &Arg_Parser::parse_RoundRects }, { "GRR", &Arg_Parser::parse_RoundRects }, { "GTrigons", &Arg_Parser::parse_Trigons }, { "GT", &Arg_Parser::parse_Trigons }, { "GArcs", &Arg_Parser::parse_Arcs }, { "GA", &Arg_Parser::parse_Arcs }, { "GArcChords", &Arg_Parser::parse_Chords }, { "GAC", &Arg_Parser::parse_Chords }, { "GArcWedges", &Arg_Parser::parse_Wedges }, { "GAW", &Arg_Parser::parse_Wedges }, { "GText", &Arg_Parser::parse_GText }, { "GX", &Arg_Parser::parse_GText }, { "GPlotColor", &Arg_Parser::parse_PlotColor }, { "GPC", &Arg_Parser::parse_PlotColor }, { "GFillColor", &Arg_Parser::parse_FillColor }, { "GFC", &Arg_Parser::parse_FillColor }, { "GColor", &Arg_Parser::parse_DrawColor }, { "GC", &Arg_Parser::parse_DrawColor }, // (terminator) { 0, 0 } }; // // Look for attribute in table: // TFE_Attr *Parser::attr_lookup (char const *attr_name, char const *attr_arg, char const *attr_end) { unsigned name_len = attr_arg - attr_name; if (*attr_name == '#') // (comment block!) return new ("Attr:Comment") TFE_A_Comment (); else if (*attr_name == '$') { // (apply user style) Arg_Parser arg_p (attr_name + 1, attr_arg, parse_mode); return new ("Attr:WithStyle") TFE_A_WithStyle (arg_p.parse_style_name ()); } Arg_Parser::Arg_Def *entry = Arg_Parser::Arg_Table; while (entry->name_attr) { unsigned len = strlen (entry->name_attr); if ((len == name_len) && (len > 1 ? (memcmp (entry->name_attr, attr_name, len) == 0) : (char_to_LC (*entry->name_attr) == char_to_LC (*attr_name)) )) { // (found attribute:) Arg_Parser arg_p (attr_arg, attr_end, parse_mode); TFE_Attr *attribute = (arg_p.*(entry->parse_attr)) (); if (arg_p.error_info) { parse_error (attr_name, attr_arg - attr_name, "Attribute argument not expected."); parse_error (attr_name, 0, arg_p.error_info); } return attribute; } ++ entry; } // (while) // (not found) parse_error (attr_name, attr_arg - attr_name, "Unknown attribute!"); return new ("Attr:Error") TFE_A_Error (attr_name, name_len, attr_arg, attr_end - attr_arg); } // Parser::attr_lookup // Parse user style definition void Parser::parse_user_style (char const *u_start, char const *u_end) { char const *u_def = skip_check_ex (u_start, u_end, cp_slash); if (u_def < u_end) { Arg_Parser arg_p (u_start, u_def, parse_mode); char const *u_name = arg_p.parse_style_name (); TFE_Attr *u_define = parse_attr (u_def + 1, u_end); append_node (new ("Def_Style") TFE_A_DefStyle (u_name, u_define)); } } // Parser::parse_user_style // Parse vertex coordinates bool Parser::parse_vertex (char const *t_start, char const *t_end, Point &point) { unsigned short mode = 0; return t_start >= t_end ? false : Arg_Parser (t_start, t_end, mode). parse_vertex (point); } // Parser::parse_vertex // // Special characters table // // // Character symdef // struct character_def { // (character name) char const *char_name; // (character codepoint) unsigned char_code; }; // Find character in table static unsigned char_lookup (character_def *table, char const *char_start, char const *char_end) { unsigned c_len = char_end - char_start; while (table->char_name) { if (memcmp (table->char_name, char_start, c_len) == 0 && table->char_name[c_len] == '\0') return table->char_code; ++ table; } // while (char_name) // (not found) return ~0; } // char_lookup // // Parse character (c_start .. c_end) // unsigned Parser::parse_character (char const *c_start, char const *c_end) { unsigned short _a_mode; unsigned value = char_lookup (character_tab, c_start, c_end); if (value == ~0) // (try parse as hex) value = Arg_Parser (c_start, c_end, _a_mode). parse_hex (); return value; } // Parser::parse_character // // Character table // character_def Parser::character_tab [] = { // blank space { ".", 0x20 }, { "iexcl", 0xA1 }, // inverse exclamation { "cent", 0xA2 }, // cent currency sign { "pound", 0xA3 }, // pound currency sign { "currency", 0xA4 }, // currency sign { "yen", 0xA5 }, // yen currency sign { "brvbar", 0xA6 }, // breve bar { "sect", 0xA7 }, // paragraph { "uml", 0xA8 }, // { "copy", 0xA9 }, // copyright { "laquo", 0xAB }, // left quote { "reg", 0xAE }, // registered trade mark { "raquo", 0xBB }, // right quote { "1/4", 0xBC }, { "1/2", 0xBD }, { "3/4", 0xBE }, { "iquest", 0xBF }, // inverse question { "times", 0xD7 }, { "divide", 0xF7 }, { "plusmin", 0xB1 }, // punctuation { "ddash", 0x2012 }, // digit dash { "ndash", 0x2013 }, // N dash { "--", 0x2013 }, { "mdash", 0x2014 }, // M dash { "---", 0x2014 }, { "...", 0x2026 }, // ellipsis { "no", 0x2116 }, // number sign { "0/00", 0x2030 }, // permille { "*", 0x2022 }, // full round bullet { "()", 0x25E6 }, // empty round bullet { "#", 0x25A0 }, // full square bullet { "[]", 0x25A1 }, // empty square bullet { "^", 0x2023 }, // trigon bullet // arrows ... // single: { "ArrowL", 0x2190 }, // arrow left { "ArrowU", 0x2191 }, // arrow up { "ArrowR", 0x2192 }, // arrow right { "ArrowD", 0x2193 }, // arrow down { "ArrowH", 0x2194 }, // arrow double horizontal { "ArrowV", 0x2195 }, // arrow double vertical // double: { "DArrowL", 0x21D0 }, // double arrow left { "DArrowU", 0x21D1 }, // double arrow up { "DArrowR", 0x21D2 }, // double arrow right { "DArrowD", 0x21D3 }, // double arrow down { "DArrowH", 0x21D4 }, // double arrow horizontal { "DArrowV", 0x21D5 }, // double arrow vertical // trigonal: { "TArrowL", 0x25C4 }, // trigon left { "TArrowU", 0x25B2 }, // trigon up { "TArrowR", 0x25BA }, // trigon right { "TArrowD", 0x25BC }, // trigon down // [ Greek capital letters ] { "Alpha", 0x0391 }, { "Beta", 0x0392 }, { "Gamma", 0x0393 }, { "Delta", 0x0394 }, { "Epsilon", 0x0395 }, { "Zeta", 0x0396 }, { "Eta", 0x0397 }, { "Theta", 0x0398 }, { "Iota", 0x0399 }, { "Kappa", 0x039A }, { "Lambda", 0x039B }, { "Mu", 0x039C }, { "Nu", 0x039D }, { "Xi", 0x039E }, { "Omicron", 0x039F }, { "Pi", 0x03A0 }, { "Rho", 0x03A1 }, { "Sigma", 0x03A3 }, { "Tau", 0x03A4 }, { "Upsilon", 0x03A5 }, { "Phi", 0x03A6 }, { "Chi", 0x03A7 }, { "Psi", 0x03A8 }, { "Omega", 0x03A9 }, // [ Greek small letters ] { "alpha", 0x03B1 }, { "beta", 0x03B2 }, { "gamma", 0x03B3 }, { "delta", 0x03B4 }, { "epsilon", 0x03B5 }, { "zeta", 0x03B6 }, { "eta", 0x03B7 }, { "theta", 0x03B8 }, { "iota", 0x03B9 }, { "kappa", 0x03BA }, { "lambda", 0x03BB }, { "mu", 0x03BC }, { "nu", 0x03BD }, { "xi", 0x03BE }, { "omicron", 0x03BF }, { "pi", 0x03C0 }, { "rho", 0x03C1 }, { "sigma", 0x03C3 }, { "tau", 0x03C4 }, { "upsilon", 0x03C5 }, { "phi", 0x03C6 }, { "chi", 0x03C7 }, { "psi", 0x03C8 }, { "omega", 0x03C9 }, // [ Hebrew letters ] { "Aleph", 0x05D0 }, { "Beth", 0x05D1 }, { "Gimel", 0x05D2 }, { "Daleth", 0x05D3 }, { "He", 0x05D4 }, { "Vav", 0x05D5 }, { "Zayin", 0x05D6 }, { "Heth", 0x05D7 }, { "Teth", 0x05D8 }, { "Yodh", 0x05D9 }, { "KaphFin", 0x05DA }, { "Kaph", 0x05DB }, { "Lamed", 0x05DC }, { "MemFin", 0x05DD }, { "Mem", 0x05DE }, { "NunFin", 0x05DF }, { "Nun", 0x05E0 }, { "Samekh", 0x05E1 }, { "Ayin", 0x05E2 }, { "PeFin", 0x05E3 }, { "Pe", 0x05E4 }, { "TsadeFin", 0x05E5 }, { "Tsade", 0x05E6 }, { "Qoph", 0x05E7 }, { "Resh", 0x05E8 }, { "Shin", 0x05E9 }, { "Tav", 0x05EA }, // [ Oghaim letters ] { "OghaimSP", 0x1680 }, { "Beith", 0x1681 }, { "Luis", 0x1682 }, { "Fearn", 0x1683 }, { "Sail", 0x1684 }, { "Nion", 0x1685 }, { "Uath", 0x1686 }, { "Dair", 0x1687 }, { "Tinne", 0x1688 }, { "Coll", 0x1689 }, { "Ceirt", 0x168A }, { "Muin", 0x168B }, { "Gort", 0x168C }, { "Ngeadal", 0x168D }, { "Straif", 0x168E }, { "Ruis", 0x168F }, { "Ailm", 0x1690 }, { "Onn", 0x1691 }, { "Ur", 0x1692 }, { "Eadhadh", 0x1693 }, { "Iadhadh", 0x1694 }, { "Eabhadh", 0x1695 }, { "Or", 0x1696 }, { "Uilleann", 0x1697 }, { "Ifin", 0x1698 }, { "Eamhancholl", 0x1699 }, { "Peith", 0x169A }, // (sequence terminator) { 0, 0 } }; // Parser::character_tab // // Color names table // static struct color_name { char const *_color_name; // (name of color) unsigned _color_value; // (value of color) } color_name_tab [] = { // // Red color names // { "MistyRose", 0xffe4e1 }, // RGB(255, 228, 225) { "Pink", 0xffc0cb }, // RGB(255, 192, 203) { "LightPink", 0xffb6c1 }, // RGB(255, 182, 193) { "LightCoral", 0xf08080 }, // RGB(240, 128, 128) { "Salmon", 0xfa8072 }, // RGB(250, 128, 114) { "RosyBrown", 0xbc8f8f }, // RGB(188, 143, 143) { "Tomato", 0xff6347 }, // RGB(255, 99, 71) { "IndianRed", 0xcd5c5c }, // RGB(205, 92, 92) { "Red", 0xff0000 }, // RGB(255, 0, 0) { "Crimson", 0xdc143c }, // RGB(220, 20, 60) { "FireBrick", 0xb22222 }, // RGB(178, 34, 34) { "Brown", 0xa52a2a }, // RGB(165, 42, 42) { "DarkRed", 0x8b0000 }, // RGB(139, 0, 0) { "Maroon" , 0x800000 }, // RGB(128, 0, 0) // // Orange color names // { "FloralWhite", 0xfffaf0 }, // RGB(255, 250, 240) { "SeaShell", 0xfff5ee }, // RGB(255, 245, 238) { "OldLace", 0xfdf5e6 }, // RGB(253, 245, 230) { "Linen", 0xfaf0e6 }, // RGB(250, 240, 230) { "PapayaWhip", 0xffefd5 }, // RGB(255, 239, 213) { "AntiqueWhite", 0xfaebd7 }, // RGB(250, 235, 215) { "BlanchedAlmond", 0xffebcd }, // RGB(255, 235, 205) { "Bisque", 0xffe4c4 }, // RGB(255, 228, 196) { "PeachPuff", 0xffdab9 }, // RGB(255, 218, 185) { "Moccasin", 0xffe4b5 }, // RGB(255, 228, 181) { "NavajoWhite", 0xffdead }, // RGB(255, 222, 173) { "Wheat", 0xf5deb3 }, // RGB(245, 222, 179) { "LightSalmon", 0xffa07a }, // RGB(255, 160, 122) { "BurlyWood", 0xdeb887 }, // RGB(222, 184, 135) { "DarkSalmon", 0xe9967a }, // RGB(233, 150, 122) { "Tan", 0xd2b48c }, // RGB(210, 180, 140) { "SandyBrown", 0xf4a460 }, // RGB(244, 164, 96) { "Coral", 0xff7f50 }, // RGB(255, 127, 80) { "Peru", 0xcd853f }, // RGB(205, 133, 63) { "DarkOrange", 0xff8c00 }, // RGB(255, 140, 0) { "Orange", 0xffa500 }, // RGB(255, 165, 0) { "OrangeRed", 0xff4500 }, // RGB(255, 69, 0) { "GoldenRod", 0xdaa520 }, // RGB(218, 165, 32) { "Chocolate", 0xd2691e }, // RGB(210, 105, 30) { "Sienna", 0xa0522d }, // RGB(160, 82, 45) { "DarkGoldenRod", 0xb8860b }, // RGB(184, 134, 11) { "SaddleBrown", 0x8b4513 }, // RGB(139, 69, 19) // // Yellow color names // { "Ivory", 0xfffff0 }, // RGB(255, 255, 240) { "LightYellow", 0xffffe0 }, // RGB(255, 255, 224) { "CornSilk", 0xfff8dc }, // RGB(255, 248, 220) { "Beige", 0xf5f5dc }, // RGB(245, 245, 220) { "LightGoldenRodYellow", 0xfafad2 }, // RGB(250, 250, 210) { "LemonChiffon", 0xfffacd }, // RGB(255, 250, 205) { "PaleGoldenRod", 0xeee8aa }, // RGB(238, 232, 170) { "Khaki", 0xf0e68c }, // RGB(240, 230, 140) { "DarkKhaki", 0xbdb76b }, // RGB(189, 183, 107) { "Gold", 0xffd700 }, // RGB(255, 215, 0) { "Yellow", 0xffff00 }, // RGB(255, 255, 0) { "Olive", 0x808000 }, // RGB(128, 128, 0) // // Yellow/Green color names // { "GreenYellow", 0xadff2f }, // RGB(173, 255, 47) { "Chartreuse", 0x7fff00 }, // RGB(127, 255, 0) { "YellowGreen", 0x9acd32 }, // RGB(154, 205, 50) { "LawnGreen", 0x7cfc00 }, // RGB(124, 252, 0) { "OliveDrab", 0x6b8e23 }, // RGB(107, 142, 35) { "DarkOliveGreen", 0x556b2f }, // RGB(85, 107, 47) // // Green color names // { "HoneyDew", 0xf0fff0 }, // RGB(240, 255, 240) { "PaleGreen", 0x98fb98 }, // RGB(152, 251, 152) { "LightGreen", 0x90ee90 }, // RGB(144, 238, 144) { "DarkSeaGreen", 0x8fbc8f }, // RGB(143, 188, 143) { "Lime", 0x00ff00 }, // RGB(0, 255, 0) { "LimeGreen", 0x32cd32 }, // RGB(50, 205, 50) { "ForestGreen", 0x228b22 }, // RGB(34, 139, 34) { "Green", 0x008000 }, // RGB(0, 128, 0) { "DarkGreen", 0x006400 }, // RGB(0, 100, 0) // // Green/Cyan color names // { "Aquamarine", 0x7fffd4 }, // RGB(127, 255, 212) { "MediumAquamarine", 0x66cdaa }, // RGB(102, 205, 170) { "SpringGreen", 0x00ff7f }, // RGB(0, 255, 127) { "MediumSpringGreen", 0x00fa9a }, // RGB(0, 250, 154) { "MediumSeaGreen", 0x3cb371 }, // RGB(60, 179, 113) { "SeaGreen", 0x2e8b57 }, // RGB(46, 139, 87) // // Cyan color names // { "Azure", 0xf0ffff }, // RGB(240, 255, 255) { "LightCyan", 0xe0ffff }, // RGB(224, 255, 255) { "PaleTurquoise", 0xafeeee }, // RGB(175, 238, 238) { "PowderBlue", 0xb0e0e6 }, // RGB(176, 224, 230) { "LightBlue", 0xadd8e6 }, // RGB(173, 216, 230) { "Turquoise", 0x40e0d0 }, // RGB(64, 224, 208) { "MediumTurquoise", 0x48d1cc }, // RGB(72, 209, 204) { "Cyan", 0x00ffff }, // RGB(0, 255, 255) { "CadetBlue", 0x5f9ea0 }, // RGB(95, 158, 160) { "DarkTurquoise", 0x00ced1 }, // RGB(0, 206, 209) { "LightSeaGreen", 0x20b2aa }, // RGB(32, 178, 170) { "DarkCyan", 0x008b8b }, // RGB(0, 139, 139) { "Teal", 0x008080 }, // RGB(0, 128, 128) { "DarkSlateGrey", 0x2f4f4f }, // RGB(47, 79, 79) // // Cyan/Blue color names // { "AliceBlue", 0xf0f8ff }, // RGB(240, 248, 255) { "LightSteelBlue", 0xb0c4de }, // RGB(176, 196, 222) { "LightSkyBlue", 0x87cefa }, // RGB(135, 206, 250) { "SkyBlue", 0x87ceeb }, // RGB(135, 206, 235) { "CornFlowerBlue", 0x6495ed }, // RGB(100, 149, 237) { "RoyalBlue", 0x4169e1 }, // RGB(65, 105, 225) { "DodgerBlue", 0x1e90ff }, // RGB(30, 144, 255) { "LightSlateGrey", 0x778899 }, // RGB(119, 136, 153) { "DeepSkyBlue", 0x00bfff }, // RGB(0, 191, 255) { "SlateGrey", 0x708090 }, // RGB(112, 128, 144) { "SteelBlue", 0x4682b4 }, // RGB(70, 130, 180) // // Blue color names // { "Lavender", 0xe6e6fa }, // RGB(230, 230, 250) { "MediumSlateBlue", 0x7b68ee }, // RGB(123, 104, 238) { "SlateBlue", 0x6a5acd }, // RGB(106, 90, 205) { "Blue", 0x0000ff }, // RGB(0, 0, 255) { "MediumBlue", 0x0000cd }, // RGB(0, 0, 205) { "DarkSlateBlue", 0x483d8b }, // RGB(72, 61, 139) { "DarkBlue", 0x00008b }, // RGB(0, 0, 139) { "MidnightBlue", 0x191970 }, // RGB(25, 25, 112) { "Navy", 0x000080 }, // RGB(0, 0, 128) // // Blue/Magenta color names // { "MediumPurple", 0x9370db }, // RGB(147, 112, 219) { "BlueViolet", 0x8a2be2 }, // RGB(138, 43, 226) { "DarkOrchid", 0x9932cc }, // RGB(153, 50, 204) { "DarkViolet", 0x9400d3 }, // RGB(148, 0, 211) { "Indigo", 0x4b0082 }, // RGB(75, 0, 130) // // Magenta color names // { "Thistle", 0xd8bfd8 }, // RGB(216, 191, 216) { "Plum", 0xdda0dd }, // RGB(221, 160, 221) { "Violet", 0xee82ee }, // RGB(238, 130, 238) { "Orchid", 0xda70d6 }, // RGB(218, 112, 214) { "MediumOrchid", 0xba55d3 }, // RGB(186, 85, 211) { "Magenta", 0xff00ff }, // RGB(255, 0, 255) { "DarkMagenta", 0x8b008b }, // RGB(139, 0, 139) { "Purple", 0x800080 }, // RGB(128, 0, 128) // // Magenta/Red color names // { "LavenderBlush", 0xfff0f5 }, // RGB(255, 240, 245) { "HotPink", 0xff69b4 }, // RGB(255, 105, 180) { "PaleVioletRed", 0xdb7093 }, // RGB(219, 112, 147) { "DeepPink", 0xff1493 }, // RGB(255, 20, 147) { "MediumVioletRed", 0xc71585 }, // RGB(199, 21, 133) // // White/Grey/Black color names // { "White", 0xffffff }, // RGB(255, 255, 255) { "Snow", 0xfffafa }, // RGB(255, 250, 250) { "GhostWhite", 0xf8f8ff }, // RGB(248, 248, 255) { "MintCream", 0xf5fffa }, // RGB(245, 255, 250) { "WhiteSmoke", 0xf5f5f5 }, // RGB(245, 245, 245) { "Gainsboro", 0xdcdcdc }, // RGB(220, 220, 220) { "LightGrey", 0xd3d3d3 }, // RGB(211, 211, 211) { "Silver", 0xc0c0c0 }, // RGB(192, 192, 192) { "DarkGrey", 0xa9a9a9 }, // RGB(169, 169, 169) { "Grey", 0x808080 }, // RGB(128, 128, 128) { "DimGrey", 0x696969 }, // RGB(105, 105, 105) { "Black", 0x000000 }, // RGB(0, 0, 0) // (terminator) { 0, 0 } }; // color_name_tab // // Parser interface ... // static A_Console *parse_output = 0; static void (* parse_handler) (char const *message, unsigned offset, unsigned length) = 0; // (trap parser errors) void set_error_handler (void (* alt_handler) (char const *message, unsigned offset, unsigned length)) { parse_handler = alt_handler; } // set_error_handler // (handle parser error here) static void parse_error (char const *message, unsigned offset, unsigned length) { if (message && parse_output) { parse_output->out_label ("Parse error:"). out_cstr (message). out_cstr (" @"). out_dec (offset). out_cstr (" #"). out_dec (length). out_nl (); if (parse_handler) parse_handler (message, offset, length); } } // parse_error // Verify source for correct parsing // (returns: #of errors) unsigned verify_source (A_Console &console, char const *source, bool word_mode, wchar_t * (* decoder_fn) (char const *source, unsigned len)) { if (source) { TFE_Term *result = 0; Parser parser (result); parse_output = &console; parser.error_handler = parse_error; parser.decoder = decoder_fn; parser.word_parse (word_mode); parser.parse_source (source); TFE_Term::release_list (result); parse_output = 0; return parser.error_count; } // (source) return 0; // (no source!) } // verify_source // Parse source // (returns: parse tree) TFE_Term *parse_source (A_Console &console, char const *source, bool word_mode, bool wrap_mode, bool dump_mode, wchar_t * (* decoder_fn) (char const *source, unsigned len)) { if (source) { TFE_Term *result = 0; Parser parser (result); parse_output = &console; parser.error_handler = parse_error; parser.decoder = decoder_fn; if (dump_mode) console.out_cstr (source).out_cstr (" => "). out_nl (); parser.word_parse (word_mode); parser.parse_source (source); parse_output = 0; if (wrap_mode) Parser::para_wrap (result); if (dump_mode) { console.dump_TFE_Tree (result); console.out_nl (); } return result; } // (source) return 0; } // parse_source // Parse attribute list // (returns: attribute list) TFE_Attr *parse_attributes (A_Console &console, char const *source) { if (source) { char const *source_end = source + strlen (source); TFE_Term *result = 0; Parser _parser (result); return _parser.parse_attr (source, source_end); } // (source) return 0; } // parse_attributes // // Dump attributes list // void dump_attributes_list (A_Console &console) { unsigned count = 0; console. out_cstr ("List of attributes:"). out_nl (); for (Arg_Parser::Arg_Def *entry = Arg_Parser::Arg_Table; entry->name_attr; ++ entry) { unsigned short attr_mode = 0; Arg_Parser _parser (0, 0, attr_mode); TFE_Attr *attr = (_parser.* (entry->parse_attr)) (); if (attr) delete attr; console.out_dec (attr_mode); console. out_tab (). out_ch ('\\'). out_cstr (entry->name_attr); if (_parser.error_info) console. out_tab (). out_qstr (_parser.error_info, '<', '>'); console. out_nl (); ++ count; } // for (entry) console. out_label ("Total attributes defined:"). out_dec (count). out_ch ('.'). out_nl (); } // dump_attributes_list // // Dump characters list // void dump_characters_list (A_Console &console) { unsigned count = 0; console. out_cstr ("List of characters:"). out_nl (); for (character_def *entry = Parser::character_tab; entry->char_name; ++ entry) { console. out_tab (). out_cstr (entry->char_name). out_tab (). out_hex (entry->char_code). out_nl (); ++ count; } // for (entry) console. out_label ("Characters defined:"). out_dec (count). out_ch ('.'). out_nl (); } // dump_characters_list // // Dump named colors // void dump_colors_list (A_Console &console) { unsigned count = 0; console. out_cstr ("List of named colors:"). out_nl (); for (color_name *entry = color_name_tab; entry->_color_name; ++ entry) { console. out_tab (). out_cstr (entry->_color_name). out_tab (). out_hex (entry->_color_value). out_nl (); ++ count; } // for (entry) console. out_label ("Colors defined:"). out_dec (count). out_ch ('.'). out_nl (); } // dump_colors_list // Release parser caches void free_caches () { // Free parser font/style cache font_cache.release (); style_cache.release (); } // free_caches // *** *** *** *** ***