jsf.jsf (21493B)
1 # JOE Syntax-Highlighting Description 2 # for 3 # JOE Syntax-Highlighting Descriptions 4 # 5 # Author: Charles J. Tabony 6 # Date: 2007-2-13 7 # 8 # This is a highlighting description for files like this one. 9 # 10 # When CHECKING is defined, it is very aggressive about error checking. The 11 # idea is that anywhere the highlighted file contains a syntax error, at least 12 # one visible character should be highlighted as Bad. While that feature is 13 # useful for finding syntax errors, it is annoying when editing a file, since 14 # nearly everything is an error until you finish typing it. 15 # 16 # In order to not annoy people by default, but keep the option of strictly 17 # checking syntax, I predicated the stricter checking on the CHECKING parameter. 18 # By default, things that are incomplete are generally not marked as errors. 19 # Only things that appear to be actual mistakes are highlighted as Bad. To 20 # enable the stricter checking, one can highlight the file with the jsf_check 21 # syntax. jsf_check.jsf simply calls the entire jsf.jsf file with CHECKING 22 # defined. 23 # 24 # The idea is for authors of a jsf file to edit their file, highlight it with 25 # jsf_check, and then look for any red characters. That way they can check for 26 # syntax errors before testing the changes. 27 28 29 30 31 ##################### 32 # Color Definitions # 33 ##################### 34 35 =Idle 36 =Comment green 37 =Conditional blue 38 =Parameter bold blue 39 =Keyword bold 40 =Color yellow 41 =StandardColor bold 42 =State 43 =Subr magenta 44 =Literal cyan 45 =Escape bold cyan 46 =Bad bold red 47 48 49 50 51 ################## 52 # Initial States # 53 ################## 54 55 # This is a dummy state that simply jumps to comment_or_bad. It is here so that 56 # when this file calls itself with the STRINGS parameter defined, comment_or_bad 57 # will effectively be the initial state. comment_or_bad should be the initial 58 # state because strings and istrings options can only be used as the last option 59 # of a transition. 60 .ifdef STRINGS 61 :strings_initial Idle 62 * comment_or_bad noeat 63 .endif 64 65 # Each new line (that is not considered bad from the beginning) begins in the 66 # idle state. The first non-whitespace character determines what the rest of 67 # the line should contain. Following a strings or istrings option, only strings 68 # and comments are allowed until the word "done" denotes the end of the list. 69 :idle Idle 70 * bad noeat 71 " \t\n" idle 72 .ifdef STRINGS 73 .else 74 "-" sync_lines_first 75 "." conditional_first mark recolor=-1 76 "=" color_definition_first 77 ":" state_first 78 "*&%" special_character recolor=-1 79 .endif 80 "\"" string recolor=-1 81 .ifdef STRINGS 82 "\i" special_word mark recolor=-1 buffer 83 .endif 84 "#" comment recolor=-1 85 86 87 ############## 88 # Sync Lines # 89 ############## 90 91 # Following a '-' should be either the number of sync lines or nothing (meaning 92 # unlimited). Nothing else other than a comment should appear on the same line. 93 .ifdef STRINGS 94 # A sync lines directive should not appear between "[i]strings" and "done". 95 .else 96 # If we see a non-digit or a '0', then we have seen the entire sync lines 97 # directive. The only thing that may appear on the rest of the line is a 98 # comment. Otherwise there may be more digits in the number. 99 :sync_lines_first Literal 100 * comment_or_bad noeat 101 "0" comment_or_bad 102 "1-9" sync_lines 103 104 # Highlight the remainder of the number. 105 :sync_lines Literal 106 * comment_or_bad noeat 107 "0-9" sync_lines 108 .endif 109 110 111 ########################## 112 # Conditional Directives # 113 ########################## 114 115 # Following a '.' should be a conditional directive. 116 .ifdef STRINGS 117 # A conditional directive should not appear between "[i]strings" and "done". 118 .else 119 # Start buffering the conditional directive. 120 :conditional_first Conditional 121 * conditional noeat buffer 122 123 # Recognize the set of conditional directives. 124 :conditional Idle 125 * conditional_unknown noeat strings 126 "ifdef" ifdef_color 127 "else" conditional_color 128 "endif" conditional_color 129 "subr" subr_color 130 "end" conditional_color 131 done 132 "\c" conditional 133 134 # We encountered what looks like a conditional directive but is unrecognized as 135 # such. 136 :conditional_unknown Idle 137 .ifdef CHECKING 138 * bad_line recolormark noeat 139 .else 140 * comment_or_bad noeat 141 .endif 142 143 # We saw a conditional directive that does not take an argument. Nothing else 144 # other than a comment should appear on the same line. 145 :conditional_color Conditional 146 * comment_or_bad noeat 147 148 # We saw a ".ifdef" which must be followed by a parameter. 149 :ifdef_color Conditional 150 * need_parameter noeat 151 152 # We loop over whitespace until we see the first character of the parameter. 153 :need_parameter Idle 154 * bad noeat 155 " \t" need_parameter 156 "\i" parameter recolor=-1 157 158 # Now we highlight the remainder of the parameter. 159 :parameter Parameter 160 * comment_or_bad noeat 161 "\c" parameter 162 163 # The following three states are identical to the previous three except the 164 # color. 165 :subr_color Conditional 166 * need_subr noeat 167 168 :need_subr Idle 169 * bad noeat 170 " \t" need_subr 171 "\i" subr recolor=-1 172 173 :subr Subr 174 * comment_or_bad noeat 175 "\c" subr 176 .endif 177 178 179 #################### 180 # Color Definition # 181 #################### 182 183 # Following an '=' should be a color definition. 184 .ifdef STRINGS 185 # Color definitions should not appear between "[i]strings" and "done". 186 .else 187 # A color name must have at least one character. 188 :color_definition_first Color 189 * color_definition 190 " \t#\n" bad noeat 191 192 # Highlight any remaining characters until we see whitespace, a comment, or a 193 # newline. 194 :color_definition Color 195 * color_definition 196 " \t#\n" colors_ws noeat 197 198 # The color name may be followed by zero or more standard colors or attributes, 199 # ending in a comment or newline. 200 :colors_ws Idle 201 * color_bad recolor=-1 202 " \t" colors_ws 203 "\i" color mark recolor=-1 buffer 204 "#\n" comment noeat 205 206 # Here we recognize the attributes and standard color names. None of the 207 # attributes or standard color names contain a digit except fg_NNN and bg_NNN, 208 # which are handled specially below. 209 :color Idle 210 * color_unknown noeat strings 211 "inverse" color_color 212 "underline" color_color 213 "bold" color_color 214 "italic" color_color 215 "blink" color_color 216 "dim" color_color 217 "white" color_color 218 "cyan" color_color 219 "magenta" color_color 220 "blue" color_color 221 "yellow" color_color 222 "green" color_color 223 "red" color_color 224 "black" color_color 225 "bg_white" color_color 226 "bg_cyan" color_color 227 "bg_magenta" color_color 228 "bg_blue" color_color 229 "bg_yellow" color_color 230 "bg_green" color_color 231 "bg_red" color_color 232 "bg_black" color_color 233 "WHITE" color_color 234 "CYAN" color_color 235 "MAGENTA" color_color 236 "BLUE" color_color 237 "YELLOW" color_color 238 "GREEN" color_color 239 "RED" color_color 240 "BLACK" color_color 241 "bg_WHITE" color_color 242 "bg_CYAN" color_color 243 "bg_MAGENTA" color_color 244 "bg_BLUE" color_color 245 "bg_YELLOW" color_color 246 "bg_GREEN" color_color 247 "bg_RED" color_color 248 "bg_BLACK" color_color 249 "fg_" color_number_first 250 "bg_" color_number_first 251 done 252 "\c" color 253 254 # We encountered what looks like a standard color but is unrecognized as such. 255 :color_unknown Idle 256 .ifdef CHECKING 257 * color_bad recolormark noeat 258 .else 259 * colors_ws noeat 260 .endif 261 262 # Here we have seen either "fg_" or "bg_". We now expect to find a number. The 263 # number should either be a one to two digit number, representing greyscale 264 # intensity, in the range 0-23, or a three digit number, where each digit is in 265 # the range 0-5 and represents the intensity of red, green, and blue 266 # respectively. 267 :color_number_first Idle 268 .ifdef CHECKING 269 * color_bad recolormark noeat 270 .else 271 * color_bad noeat 272 .endif 273 "0" color_zero 274 "1" color_one 275 "2" color_two 276 "3-5" color_number_second 277 "6-9" color_end 278 279 # The first digit is a zero, thus we either have a greyscale intensity of 0, in 280 # which case we should not see any more digits, or we have the first RGB digit, 281 # in which case we should see two more ditits in the range 0-5. 282 :color_zero Idle 283 .ifdef CHECKING 284 * color_bad recolormark noeat 285 .else 286 * color_bad noeat 287 .endif 288 "0-5" color_rgb_third 289 " \t#\n" color_color recolormark noeat 290 291 # The first digit is a one. If we see whitespace or a comment, then we have a 292 # greyscale intensity of 1. If we see a digit 6-9, then we have a greyscale 293 # intensity of 16-19. If we see a digit 0-5, then we either have a greyscale 294 # intensity of 10-15 or an RGB value. 295 :color_one Idle 296 .ifdef CHECKING 297 * color_bad recolormark noeat 298 .else 299 * color_bad noeat 300 .endif 301 "0-5" color_number_third 302 "6-9" color_end 303 " \t#\n" color_color recolormark noeat 304 305 # The first digit is a two. If we see whitespace or a comment, then we have a 306 # greyscale intensity of 2. If we see a digit 4-5, then we have the first two 307 # digits of an RGB value. If we see a digit 0-3, then we either have a 308 # greyscale intensity of 20-23 or an RGB value. 309 :color_two Idle 310 .ifdef CHECKING 311 * color_bad recolormark noeat 312 .else 313 * color_bad noeat 314 .endif 315 "0-3" color_number_third 316 "4-5" color_rgb_third 317 " \t#\n" color_color recolormark noeat 318 319 # We have seen one digit that could be either the greyscale intensity or the 320 # first RGB digit. If we see any more digits, they we must have an RGB value, 321 # because otherwise the number would be outside the range 0-23. 322 :color_number_second Idle 323 .ifdef CHECKING 324 * color_bad recolormark noeat 325 .else 326 * color_bad noeat 327 .endif 328 "0-5" color_rgb_third 329 " \t#\n" color_color recolormark noeat 330 331 # We have seen two digits that could be either the greyscale intensity or the 332 # first two RGB digits. If we see any more digits, they we must have an RGB 333 # value, because otherwise the number would be outside the range 0-23. 334 :color_number_third Idle 335 .ifdef CHECKING 336 * color_bad recolormark noeat 337 .else 338 * color_bad noeat 339 .endif 340 "0-5" color_end 341 " \t#\n" color_color recolormark noeat 342 343 # We have seen two digits, both 0-5, that either start with zero or are outside 344 # the range 0-23. Thus we expect a third 0-5 digit. 345 :color_rgb_third Idle 346 .ifdef CHECKING 347 * color_bad recolormark noeat 348 .else 349 * color_bad noeat 350 .endif 351 "0-5" color_end 352 353 # We have seen "fg_" or "bg_" followed by one to three digits. Any more digits 354 # would either be too many or make the number out of range. We now expect to 355 # see whitespace, a comment, or a newline. 356 :color_end Idle 357 .ifdef CHECKING 358 * color_bad recolormark noeat 359 .else 360 * color_bad noeat 361 .endif 362 " \t#\n" color_color recolormark noeat 363 364 # This is a dummy state that simply provides the highlighting color for the 365 # standard color or attribute and jumps to colors_ws without consuming any 366 # characters. 367 :color_color StandardColor 368 * colors_ws noeat 369 370 # We have encountered something that is not recognized as a standard color or 371 # attribute. Continue to highlight characters as Bad until we see whitespace, a 372 # comment, or a newline. 373 :color_bad Bad 374 * color_bad 375 " \t#\n" colors_ws noeat 376 .endif 377 378 379 ######### 380 # State # 381 ######### 382 383 # Following a ':' should be a state definition. 384 .ifdef STRINGS 385 # New states should not appear between "[i]strings" and "done". 386 .else 387 # A state name must begin with an alpha character or an underscore. 388 :state_first State 389 * bad noeat 390 "\i" state 391 392 # Subsequent characters in a state name must be alpha-numeric or underscores. 393 :state State 394 * bad noeat 395 "\c" state 396 " \t" need_state_color recolor=-1 397 398 # A state must have a color. 399 :need_state_color Idle 400 * state_color recolor=-1 401 " \t" need_state_color 402 "#\n" bad noeat 403 404 # Highlight any remaining characters until we see whitespace, a comment, or a 405 # newline. 406 :state_color Color 407 * state_color 408 " \t" context_ws recolor=-1 409 "#\n" comment_or_bad noeat 410 411 # Following the state color, there might be one or more contexts. Loop over 412 # whitespace until we find something else. 413 :context_ws Idle 414 * comment_or_bad noeat 415 " \t" context_ws 416 "\i" context mark recolor=-1 buffer 417 418 # Here we recognize the possible contexts. 419 :context Idle 420 * context_unknown noeat strings 421 "comment" context_color 422 "string" context_color 423 done 424 "\c" context 425 426 # We encountered what looks like a context but is unrecognized as such. 427 :context_unknown Idle 428 .ifdef CHECKING 429 * context_bad recolormark noeat 430 .else 431 * context_ws noeat 432 .endif 433 434 # We encountered a valid context. 435 :context_color Keyword 436 * context_ws noeat 437 438 # We saw something that is not a valid context name with checking enabled. 439 # Continue to highlight it as Bad until we see whitespace or a comment. 440 :context_bad Bad 441 * context_bad 442 " \t#\n" context_ws noeat 443 .endif 444 445 446 ############## 447 # Transition # 448 ############## 449 450 # A state transition starts with a '*', an '&', or a string. 451 .ifdef STRINGS 452 # Transitions must start with a string between "[i]strings" and "done". 453 .else 454 # We saw either a '*' or an '&'. Now we need the next state. 455 :special_character Keyword 456 * need_next_state noeat 457 .endif 458 459 # We are in a string. Continue until we see the close quote or a newline. 460 # Highlight escaped characters within the string differently. They start with a 461 # '\'. 462 :string Literal string 463 * string 464 "\\" escape recolor=-1 465 "\"" need_next_state 466 .ifdef CHECKING 467 "\n" bad 468 .else 469 "\n" bad noeat 470 .endif 471 472 # Highlight an escaped character within a string. 473 :escape Escape string 474 * string 475 476 # Loop over whitespace until we see the first character of the next state. 477 :need_next_state Idle 478 * bad noeat 479 " \t" need_next_state 480 "\i" next_state recolor=-1 481 482 # Now we highlight the remainder of the next state. 483 :next_state State 484 * bad noeat 485 "\c" next_state 486 " \t" options_ws 487 "#\n" comment noeat 488 489 # Following the next state should be zero or more options. Loop over whitespace 490 # until we find an option, comment, or newline. 491 :options_ws Idle 492 * option_bad recolor=-1 493 " \t" options_ws 494 "\i" option mark recolor=-1 buffer 495 "#\n" comment noeat 496 497 # Here we recognize the possible options. The strings and istrings options 498 # cannot be used between "[i]strings" and "done". Since conditional directives 499 # cannot be used between "[i]strings" and "done" either, the list must be 500 # duplicated, once without and once with the strings and istrings options. 501 :option Idle 502 .ifdef STRINGS 503 * option_unknown recolormark noeat strings 504 "noeat" option_color 505 "recolor" recolor_color 506 "mark" option_color 507 "markend" option_color 508 "recolormark" option_color 509 "buffer" option_color 510 "save_c" option_color 511 "save_s" option_color 512 "hold" option_color 513 "call" call_color 514 "return" option_color 515 "reset" option_color 516 done 517 .else 518 * option_unknown recolormark noeat strings 519 "noeat" option_color 520 "recolor" recolor_color 521 "mark" option_color 522 "markend" option_color 523 "recolormark" option_color 524 "buffer" option_color 525 "save_c" option_color 526 "save_s" option_color 527 "strings" strings_color 528 "istrings" strings_color 529 "hold" option_color 530 "call" call_color 531 "return" option_color 532 "reset" option_color 533 done 534 .endif 535 "\c" option 536 537 # We encountered what looks like an option but is unrecognized as such. 538 :option_unknown Idle 539 .ifdef CHECKING 540 * option_bad recolormark noeat 541 .else 542 * options_ws noeat 543 .endif 544 545 # We have encountered an option that does not take an argument. Highlight it 546 # and continue to look for more options. 547 :option_color Keyword 548 * options_ws noeat 549 550 .ifdef STRINGS 551 # The strings and istrings options cannot be used between "[i]strings" and 552 # "done". 553 .else 554 # The strings and istrings options are followed by a list of transitions. 555 # Rather than duplicate all of the states that highlight transitions, we call 556 # this entire file as a subroutine and use the STRINGS parameter to disable 557 # everything else and enable the done keyword. We return to the comment_or_bad 558 # state since we will return after seeing the done keyword, and nothing but a 559 # comment should follow the done keyword. 560 :strings_color Keyword 561 * comment_or_bad noeat call=jsf(STRINGS) 562 .endif 563 564 # Highlight the recolor option. 565 :recolor_color Keyword 566 * recolor_equal noeat 567 568 # The recolor option must be followed by an '='. Loop over whitespace until we 569 # find one. 570 :recolor_equal Idle 571 .ifdef CHECKING 572 * option_bad recolormark noeat 573 .else 574 * options_ws noeat 575 .endif 576 " \t" recolor_equal 577 "=" recolor_minus mark 578 579 # The recolor option takes an integer argument, and that integer must be 580 # negative. Thus the '=' must be followed by a minus sign. Loop over 581 # whitespace until we find one. 582 :recolor_minus Idle 583 .ifdef CHECKING 584 * option_bad recolormark noeat 585 .else 586 * options_ws noeat 587 .endif 588 " \t" recolor_minus 589 "-" recolor_amount_first mark recolor=-1 590 591 # The first digit of the argument to recolor must be non-zero. 592 :recolor_amount_first Literal 593 .ifdef CHECKING 594 * option_bad recolormark noeat 595 .else 596 * options_ws recolormark noeat 597 "0" option_bad recolormark noeat 598 .endif 599 "1-9" recolor_amount 600 601 # Keep highlighting digits until we see something else. 602 :recolor_amount Literal 603 * option_bad recolormark recolor=-1 604 "0-9" recolor_amount 605 " \t#\n" options_ws noeat 606 607 # Highlight the call option. 608 :call_color Keyword 609 * call_equal noeat 610 611 # The call option must be followed by an '='. Loop over whitespace until we 612 # find one. 613 :call_equal Idle 614 .ifdef CHECKING 615 * option_bad recolormark noeat 616 .else 617 * options_ws noeat 618 .endif 619 " \t" call_equal 620 "=" call_file_or_dot mark 621 622 # The first part of the argument to the call option is the name of the file 623 # containing the subroutine or a '.', implying the current file. Loop over 624 # whitespace until we see one of those two things. 625 :call_file_or_dot Idle 626 .ifdef CHECKING 627 * option_bad recolormark noeat 628 .else 629 * options_ws noeat 630 .endif 631 " \t" call_file_or_dot 632 "\i" call_file mark recolor=-1 633 "." call_dot mark 634 635 # Highlight the remainder of the file name. The file name can be followed by a 636 # '.', which must then be followed by the name of a subroutine, or by a list of 637 # parameters in parentheses. The '.', if present, cannot have whitespace on 638 # either side. 639 :call_file Subr 640 .ifdef CHECKING 641 * option_bad recolormark noeat 642 .else 643 * options_ws noeat 644 .endif 645 "\c" call_file 646 "." call_dot mark recolor=-1 647 " \t(" call_open_paren noeat 648 649 # We saw a '.'. The next character must start the name of a subroutine. 650 :call_dot Idle 651 .ifdef CHECKING 652 * option_bad recolormark noeat 653 .else 654 * options_ws noeat 655 .endif 656 "(" call_dot_bad recolormark noeat 657 "\i" call_subr mark recolor=-1 658 659 # We have seen a dot followed by an open parenthesis. A dot must be followed by 660 # a subroutine name. Highlight the dot as Bad. 661 :call_dot_bad Bad 662 * call_open_paren noeat 663 664 # Highlight the remainder of the subroutine name. Following the subroutine name 665 # must be a list of parameters in parentheses, possibly preceded by whitespace. 666 :call_subr Subr 667 .ifdef CHECKING 668 * option_bad recolormark noeat 669 .else 670 * options_ws noeat 671 .endif 672 "\c" call_subr 673 " \t(" call_open_paren noeat 674 675 # Loop over whitespace until we find the open parenthesis. 676 :call_open_paren Idle 677 .ifdef CHECKING 678 * option_bad recolormark noeat 679 .else 680 * options_ws noeat 681 .endif 682 " \t" call_open_paren 683 "(" call_parameters_ws 684 685 # The list of parameters is delimited by whitespace. Loop over whitespace until 686 # we find either the beginning of a parameter or a close parenthesis. We should 687 # not see a comment or newline since the list should be terminated by a close 688 # parenthesis. 689 :call_parameters_ws Idle 690 * call_parameter_bad recolor=-1 691 " \t" call_parameters_ws 692 "-" call_parameter_undef 693 "\i" call_parameter recolor=-1 694 ")" options_ws 695 "#\n" bad noeat 696 697 # We saw a "-". The next character should start the parameter being undefined. 698 :call_parameter_undef Parameter 699 * call_parameters_ws noeat 700 "\i" call_parameter recolor=-2 701 702 # Highlight the remainder of the parameter. 703 :call_parameter Parameter 704 * call_parameters_ws noeat 705 "\c" call_parameter 706 707 # We saw something that is not a valid parameter name. Continue to highlight it 708 # as Bad until we see whitespace. 709 :call_parameter_bad Bad 710 * call_parameter_bad 711 ") \t#\n" call_parameters_ws noeat 712 713 # We saw something that is not a valid option name. Continue to highlight it as 714 # Bad until we see whitespace or a comment. 715 :option_bad Bad 716 * option_bad 717 " \t#\n" options_ws noeat 718 719 720 ######## 721 # Done # 722 ######## 723 724 .ifdef STRINGS 725 # The special word, "done", can only be used after a strings or istrings option. 726 # Recognize the done keyword. 727 :special_word Idle 728 * bad_line recolormark noeat strings 729 "done" done_color 730 done 731 "\c" special_word 732 733 # Highlight the done keyword and return to highlighting things normally, since 734 # the list of strings has been terminated. 735 :done_color Keyword 736 * comment_or_bad return noeat 737 .endif 738 739 740 ################## 741 # Comment or Bad # 742 ################## 743 744 # We have seen everything that should appear on the current line except an 745 # optional comment. Loop over whitespace until we find a comment or newline. 746 :comment_or_bad Idle 747 * bad noeat 748 " \t" comment_or_bad 749 "#\n" comment noeat 750 751 752 ########### 753 # Comment # 754 ########### 755 756 # Continue to highlight the comment until the end of the line. 757 :comment Comment comment 758 * comment 759 "\n" idle 760 761 762 ####### 763 # Bad # 764 ####### 765 766 .ifdef CHECKING 767 # We have encountered incorrect syntax. Loop over whitespace until we see the 768 # first visible character. Highlight that character and the rest of the line as 769 # Bad. 770 :bad Bad 771 * bad_line 772 " \t\n" bad 773 .else 774 # When not performing strict checking, don't go searching for the next visible 775 # character to highlight as Bad. Simply highlight the rest of the line as Bad, 776 # even if it is invisible. 777 :bad Bad 778 * bad_line noeat 779 .endif 780 781 # Continue to highlight everything as Bad until the end of the line. 782 :bad_line Bad 783 * bad_line 784 "\n" idle