📄 syntax.c
字号:
info->strnewl = TRUE; else { residue = parse_token( residue, key ); if (strlen( key ) != 1 || bj_isalnum( *key )) { ERRORLINE( syntax7, key ); } else info->strspan = *key; } } } } break; case SHL_CHARACTER: if (info->identifier[U( *key )] & ID_STARTWORD) add_keyword_list( syntax, key_no, key, residue ); else { if (strlen( key ) > 2) { ERRORLINE( syntax8a, key ); } else { /* * Characters are the same as strings, but they also have a * length limit. */ if (key[1] == '\0') { info->charstart = key[0]; number = parse_token( residue, key ); if (*key && key[1] == '\0' && !bj_isdigit( *key ) ) { info->charend = key[0]; residue = number; } else info->charend = info->charstart; } else { info->charstart = key[0]; info->charend = key[1]; } for (;;) { residue = parse_token( residue, key ); if (*key == '\0' || *key == ';') break; if (bj_isdigit( *key )) { info->charnum = atoi( key ); if (info->charnum) ++info->charnum; /* add one for closing quote */ continue; } key_no = search( key, valid_string, 1 ); if (key_no == ERROR) { ERRORLINE( syntax5, key ); continue; } if (key_no == SHL_NEWLINE) info->charnewl = TRUE; else { residue = parse_token( residue, key ); if (strlen( key ) != 1 || bj_isalnum( *key )) { ERRORLINE( syntax7, key ); } else info->charspan = *key; } } } } break; case SHL_MENU: { const char* errmsg = new_user_menu( residue, key, TRUE ); if (errmsg != NULL) { ERRORLINE( errmsg, key ); } break; } case SHL_INFLATETABS: key_no = search( key, valid_tabs, 2 ); if (key_no == ERROR) { ERRORLINE( config16, key ); continue; } syntax->inflate_tabs = key_no; break; case SHL_PTABSIZE : case SHL_LTABSIZE : i = atoi( key ); if (i > MAX_TAB_SIZE || i < 1) { ERRORLINE( config8, key ); continue; } if (key_no == SHL_PTABSIZE) syntax->ptab_size = i; else syntax->ltab_size = i; break; case SHL_KEYWORD: case SHL_NORMAL: case SHL_BAD: case SHL_SYMBOL: case SHL_INTEGER: case SHL_REAL: default: add_keyword_list( syntax, key_no, key, residue ); } }}#undef U/* * Name: add_keyword_list * Purpose: add a line of keywords to the syntax highlighting info * Passed: syntax: syntax structure containing the keywords * color: color of the keywords * key: first keyword * residue: rest of the keywords */void add_keyword_list( LANGUAGE *syntax, int color, char *key, char *residue ){ if (color >= 256) color = syntax_color[color - 256]; while (*key != '\0' && !out_of_memory) { add_keyword( syntax, key, color ); residue = parse_token( residue, key ); }}/* * Name: add_keyword * Purpose: update the keyword list * Passed: syntax: syntax structure containing the keywords * key: keyword * color: color of the keyword * Notes: uses a hash table based on the first two characters. * The first character is the color, the rest is the word itself. */void add_keyword( LANGUAGE *syntax, char *key, int color ){text_ptr keyword;int hash;text_ptr *hashed;int i;int len;int rc = OK; /* * Add the keyword if it doesn't already exist. */ if ((keyword = is_keyword( syntax, key, FALSE )) == NULL) { len = strlen( key ) + 1; keyword = (text_ptr)my_malloc( len + 1, &rc ); if (rc == OK) { my_memcpy( keyword+1, key, len ); hash = KWHASH( key ); /* * Create a bigger array. */ if (syntax->keyword[hash]) { /* * Find the number of words already allocated. */ for (i = 0; syntax->keyword[hash][i]; ++i) ; hashed = (text_ptr *)my_malloc( (i+2) * sizeof(text_ptr), &rc ); if (rc == OK) { for (; i >= 0; --i) hashed[i+1] = syntax->keyword[hash][i]; my_free( syntax->keyword[hash] ); } } else { /* * Start a new list. */ hashed = (text_ptr *)my_malloc( 2 * sizeof(text_ptr), &rc ); if (rc == OK) hashed[1] = NULL; } if (hashed == NULL) my_free( keyword ); else { syntax->keyword[hash] = hashed; syntax->keyword[hash][0] = keyword; } } if (rc == ERROR) { /* * out of memory */ error( WARNING, prompt_line, main4 ); out_of_memory = TRUE; return; } } keyword[0] = color;}/* * Name: is_keyword * Purpose: determine if a string is a keyword * Passed: syntax: pointer to the syntax info * word: string to test * parent: TRUE to scan the parent language's keywords. * Returns: pointer to the keyword if it exists, NULL otherwise */text_ptr is_keyword( LANGUAGE *syntax, char *word, int parent ){int hash;int i; hash = KWHASH( word ); if (syntax->keyword[hash] != NULL) for (i = 0; syntax->keyword[hash][i]; ++i) if (!my_strcmp( syntax->keyword[hash][i]+1, (text_ptr)word )) return( syntax->keyword[hash][i] ); return( (parent && syntax->parent) ? is_keyword( syntax->parent, word, parent ) : NULL );}/* * Name: syntax_init_colors * Purpose: set the colors for the syntax highlighting components * Passed: fp: file pointer of syntax file * Notes: goes back to the start of the file, reads the colors, and * restores the file position. * 990421: modified to use the new parse_color() function. */void syntax_init_colors( FILE *fp ){long pos; /* current position in the file */unsigned old_line; /* current line number of the file */char *color;int key;char col[1042];int color_no;const char *errmsg = NULL; pos = ftell( fp ); rewind( fp ); old_line = line_no; line_no = 0; for (;;) { key = syntax_read_line( fp, &color ); if (key == SHL_LANGUAGE) break; if ((key > SHL_SYMBOL || key < SHL_NORMAL) && key != SHL_BACKGROUND) errmsg = syntax3; else { color_no = parse_color( &color, col, prompt_line, config6a ); if (color_no != ERROR) { if (key == SHL_BACKGROUND) { color_no >>= 4; background = color_no & 15; } else syntax_color[key - 256] = color_no; } } if (errmsg != NULL) { ERRORLINE( errmsg, col ); errmsg = NULL; } } fseek( fp, pos, SEEK_SET ); line_no = old_line;}/* * Name: syntax_init_lines * Purpose: set the initial line flags for syntax highlighting * Passed: file: pointer to the file to be initialized * * 060915: set the tab settings. */void syntax_init_lines( file_infos *file ){syntax_info *syntax;line_list_ptr ll; /* * No point doing this if the file doesn't have highlighting. */ if (file->syntax != NULL) { syntax = file->syntax->info; ll = file->line_list->next; while (ll->len != EOF) { syntax_check( ll, syntax ); ll = ll->next; } if (g_option.tab_size == -1) { if (file->syntax->inflate_tabs != ERROR) file->inflate_tabs = file->syntax->inflate_tabs; if (file->syntax->ptab_size) file->ptab_size = file->syntax->ptab_size; } if (file->syntax->ltab_size) file->ltab_size = file->syntax->ltab_size; }}/* * Name: match_comment * Purpose: determine if the line contains a comment * Author: Jason Hood * Date: November 23, 2001 * Passed: comment: comment to test * line: line to test against * pos: position in line to start test * len: length of line * Returns: length of the comment, or 0 if no match * Notes: comment should exist (ie. be at least one character). */static int match_comment( text_ptr comment, text_ptr line, int pos, int len ){text_ptr start = comment; line += pos; len -= pos; while (*comment == *line++ && *++comment && --len); if (*comment == '\0') return( (int)(comment - start) ); return( 0 );}/* * Name: syntax_check * Purpose: determine the syntax highlighting flags for a line * Passed: line: line to test * syntax: language to test against * Notes: The previous line must have the right flags. * * This function is used to determine what type of line a line is. It enables * us to jump to any part of the file, without the need to backtrack to see if * we're in a comment or string, like Elvis does. As such, it's only required * for the stuff that uses multiple lines, namely comments, strings, characters * and some preprocessors (like C). However, if these start and finish in the * one line, there's no need to type them, since they have no effect on * subsequent lines. * * Comments (COM), strings (STR) and characters (CHR) consist of three * components: _START, _WHOLE and _END. _START means it begins somewhere on the * line and extends to the end of the line; _WHOLE means the entire line is * occupied; _END means it continues from the beginning of the line, but stops * somewhere. _START and _WHOLE are used to "inherit" the new line type from * the previous line. _WHOLE and _END are used to indicate that this line is * still (partly) a comment, string or character, for display purposes (ie. * syntax_attr()) - which is the whole point of doing this typing. * * Strings and characters also have START_VALID, WHOLE_VALID and END_VALID * values, which indicates if it is actually legally allowed to span multiple * lines. (Note that they always do span lines, they never stop at eol, like * some versions of BASIC allowed.) * * Preprocessor is a little different, since it always occupies the whole line, * but can still have the above components. So it has PREPRO to indicate that * the line is a preprocessor, and _START and _END components to indicate the * first and last lines of the preprocessor. The new line will be PREPRO if the * last line was PREPRO, but not PREPRO_END. PREPRO_START is used in * syntax_attr() to indicate that we should still test for preprocessor, so * leading blanks will be done in normal, and preprocessor will be recognized * before comment (with Pascal's {$ and shell scripts' #!, for example). * * jmh 030411: fixed bug with spanning (this wasn't set correctly). */void syntax_check( line_list_ptr line, syntax_info *syntax ){text_ptr ll;int len;long old_type; /* type of the previous line */long type; /* type of this line */int in_comment;int in_string;int in_character;int in_prepro;text_t this, next;int com_len, com_num;long com_bit;int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -