628 lines
16 KiB
Plaintext
628 lines
16 KiB
Plaintext
|
# JOE Syntax-Highlighting Description
|
||
|
# for
|
||
|
# JOE Syntax-Highlighting Descriptions
|
||
|
#
|
||
|
# Author: Charles J. Tabony
|
||
|
# Date: 2007-2-13
|
||
|
#
|
||
|
# This is a highlighting description for files like this one.
|
||
|
#
|
||
|
# When CHECKING is defined, it is very aggressive about error checking. The
|
||
|
# idea is that anywhere the highlighted file contains a syntax error, at least
|
||
|
# one visible character should be highlighted as Bad. While that feature is
|
||
|
# useful for finding syntax errors, it is annoying when editing a file, since
|
||
|
# nearly everything is an error until you finish typing it.
|
||
|
#
|
||
|
# In order to not annoy people by default, but keep the option of strictly
|
||
|
# checking syntax, I predicated the stricter checking on the CHECKING parameter.
|
||
|
# By default, things that are incomplete are generally not marked as errors.
|
||
|
# Only things that appear to be actual mistakes are highlighted as Bad. To
|
||
|
# enable the stricter checking, one can highlight the file with the jsf_check
|
||
|
# syntax. jsf_check.jsf simply calls the entire jsf.jsf file with CHECKING
|
||
|
# defined.
|
||
|
#
|
||
|
# The idea is for authors of a jsf file to edit their file, highlight it with
|
||
|
# jsf_check, and then look for any red characters. That way they can check for
|
||
|
# syntax errors before testing the changes.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#####################
|
||
|
# Color Definitions #
|
||
|
#####################
|
||
|
|
||
|
=Idle
|
||
|
=Comment
|
||
|
=Conditional +Precond +Preproc
|
||
|
=Parameter +Ident
|
||
|
=Keyword
|
||
|
=Color +Type
|
||
|
=ColorRef
|
||
|
=State +Ident
|
||
|
=Subr +Ident
|
||
|
=Constant
|
||
|
=Number +Constant
|
||
|
=String +Constant
|
||
|
=StringEscape +Escape +String
|
||
|
=Bad
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
##################
|
||
|
# Initial States #
|
||
|
##################
|
||
|
|
||
|
# This is a dummy state that simply jumps to comment_or_bad. It is here so that
|
||
|
# when this file calls itself with the STRINGS parameter defined, comment_or_bad
|
||
|
# will effectively be the initial state. comment_or_bad should be the initial
|
||
|
# state because strings and istrings options can only be used as the last option
|
||
|
# of a transition.
|
||
|
.ifdef STRINGS
|
||
|
:strings_initial Idle
|
||
|
* comment_or_bad noeat
|
||
|
.endif
|
||
|
|
||
|
# Each new line (that is not considered bad from the beginning) begins in the
|
||
|
# idle state. The first non-whitespace character determines what the rest of
|
||
|
# the line should contain. Following a strings or istrings option, only strings
|
||
|
# and comments are allowed until the word "done" denotes the end of the list.
|
||
|
:idle Idle
|
||
|
* bad noeat
|
||
|
" \t\n" idle
|
||
|
.ifdef STRINGS
|
||
|
.else
|
||
|
"-" sync_lines_first
|
||
|
"." conditional_first mark recolor=-1
|
||
|
"=" color_definition_first
|
||
|
":" state_first
|
||
|
"*&%" special_character recolor=-1
|
||
|
.endif
|
||
|
"\"" string recolor=-1
|
||
|
.ifdef STRINGS
|
||
|
"\i" special_word mark recolor=-1 buffer
|
||
|
.endif
|
||
|
"#" comment recolor=-1
|
||
|
|
||
|
|
||
|
##############
|
||
|
# Sync Lines #
|
||
|
##############
|
||
|
|
||
|
# Following a '-' should be either the number of sync lines or nothing (meaning
|
||
|
# unlimited). Nothing else other than a comment should appear on the same line.
|
||
|
.ifdef STRINGS
|
||
|
# A sync lines directive should not appear between "[i]strings" and "done".
|
||
|
.else
|
||
|
# If we see a non-digit or a '0', then we have seen the entire sync lines
|
||
|
# directive. The only thing that may appear on the rest of the line is a
|
||
|
# comment. Otherwise there may be more digits in the number.
|
||
|
:sync_lines_first Number
|
||
|
* comment_or_bad noeat
|
||
|
"0" comment_or_bad
|
||
|
"1-9" sync_lines
|
||
|
|
||
|
# Highlight the remainder of the number.
|
||
|
:sync_lines Number
|
||
|
* comment_or_bad noeat
|
||
|
"0-9" sync_lines
|
||
|
.endif
|
||
|
|
||
|
|
||
|
##########################
|
||
|
# Conditional Directives #
|
||
|
##########################
|
||
|
|
||
|
# Following a '.' should be a conditional directive.
|
||
|
.ifdef STRINGS
|
||
|
# A conditional directive should not appear between "[i]strings" and "done".
|
||
|
.else
|
||
|
# Start buffering the conditional directive.
|
||
|
:conditional_first Conditional
|
||
|
* conditional noeat buffer
|
||
|
|
||
|
# Recognize the set of conditional directives.
|
||
|
:conditional Idle
|
||
|
* conditional_unknown noeat strings
|
||
|
"ifdef" ifdef_color
|
||
|
"else" conditional_color
|
||
|
"endif" conditional_color
|
||
|
"subr" subr_color
|
||
|
"end" conditional_color
|
||
|
done
|
||
|
"\c" conditional
|
||
|
|
||
|
# We encountered what looks like a conditional directive but is unrecognized as
|
||
|
# such.
|
||
|
:conditional_unknown Idle
|
||
|
.ifdef CHECKING
|
||
|
* bad_line recolormark noeat
|
||
|
.else
|
||
|
* comment_or_bad noeat
|
||
|
.endif
|
||
|
|
||
|
# We saw a conditional directive that does not take an argument. Nothing else
|
||
|
# other than a comment should appear on the same line.
|
||
|
:conditional_color Conditional
|
||
|
* comment_or_bad noeat
|
||
|
|
||
|
# We saw a ".ifdef" which must be followed by a parameter.
|
||
|
:ifdef_color Conditional
|
||
|
* need_parameter noeat
|
||
|
|
||
|
# We loop over whitespace until we see the first character of the parameter.
|
||
|
:need_parameter Idle
|
||
|
* bad noeat
|
||
|
" \t" need_parameter
|
||
|
"\i" parameter recolor=-1
|
||
|
|
||
|
# Now we highlight the remainder of the parameter.
|
||
|
:parameter Parameter
|
||
|
* comment_or_bad noeat
|
||
|
"\c" parameter
|
||
|
|
||
|
# The following three states are identical to the previous three except the
|
||
|
# color.
|
||
|
:subr_color Conditional
|
||
|
* need_subr noeat
|
||
|
|
||
|
:need_subr Idle
|
||
|
* bad noeat
|
||
|
" \t" need_subr
|
||
|
"\i" subr recolor=-1
|
||
|
|
||
|
:subr Subr
|
||
|
* comment_or_bad noeat
|
||
|
"\c" subr
|
||
|
.endif
|
||
|
|
||
|
|
||
|
####################
|
||
|
# Color Definition #
|
||
|
####################
|
||
|
|
||
|
# Following an '=' should be a color definition.
|
||
|
.ifdef STRINGS
|
||
|
# Color definitions should not appear between "[i]strings" and "done".
|
||
|
.else
|
||
|
# A color name must have at least one character.
|
||
|
:color_definition_first Color
|
||
|
* color_definition
|
||
|
" \t#\n" bad noeat
|
||
|
|
||
|
# Highlight any remaining characters until we see whitespace, a comment, or a
|
||
|
# newline.
|
||
|
:color_definition Color
|
||
|
* color_definition
|
||
|
" \t#\n" colors_ws noeat
|
||
|
|
||
|
# The color name may be followed by zero or more standard colors or attributes,
|
||
|
# ending in a comment or newline.
|
||
|
:colors_ws Idle
|
||
|
* color_bad recolor=-1
|
||
|
" \t" colors_ws
|
||
|
"+" color_ref recolor=-1
|
||
|
"#\n" comment noeat
|
||
|
|
||
|
:color_ref ColorRef
|
||
|
* colors_ws noeat
|
||
|
"\c" color_ref
|
||
|
|
||
|
# We have encountered something that is not recognized as a standard color or
|
||
|
# attribute. Continue to highlight characters as Bad until we see whitespace, a
|
||
|
# comment, or a newline.
|
||
|
:color_bad Bad
|
||
|
* color_bad
|
||
|
" \t#\n" colors_ws noeat
|
||
|
.endif
|
||
|
|
||
|
|
||
|
#########
|
||
|
# State #
|
||
|
#########
|
||
|
|
||
|
# Following a ':' should be a state definition.
|
||
|
.ifdef STRINGS
|
||
|
# New states should not appear between "[i]strings" and "done".
|
||
|
.else
|
||
|
# A state name must begin with an alpha character or an underscore.
|
||
|
:state_first State
|
||
|
* bad noeat
|
||
|
"\i" state
|
||
|
|
||
|
# Subsequent characters in a state name must be alpha-numeric or underscores.
|
||
|
:state State
|
||
|
* bad noeat
|
||
|
"\c" state
|
||
|
" \t" need_state_color recolor=-1
|
||
|
|
||
|
# A state must have a color.
|
||
|
:need_state_color Idle
|
||
|
* state_color recolor=-1
|
||
|
" \t" need_state_color
|
||
|
"#\n" bad noeat
|
||
|
|
||
|
# Highlight any remaining characters until we see whitespace, a comment, or a
|
||
|
# newline.
|
||
|
:state_color Color
|
||
|
* state_color
|
||
|
" \t" context_ws recolor=-1
|
||
|
"#\n" comment_or_bad noeat
|
||
|
|
||
|
# Following the state color, there might be one or more contexts. Loop over
|
||
|
# whitespace until we find something else.
|
||
|
:context_ws Idle
|
||
|
* comment_or_bad noeat
|
||
|
" \t" context_ws
|
||
|
"\i" context mark recolor=-1 buffer
|
||
|
|
||
|
# Here we recognize the possible contexts.
|
||
|
:context Idle
|
||
|
* context_unknown noeat strings
|
||
|
"comment" context_color
|
||
|
"string" context_color
|
||
|
done
|
||
|
"\c" context
|
||
|
|
||
|
# We encountered what looks like a context but is unrecognized as such.
|
||
|
:context_unknown Idle
|
||
|
.ifdef CHECKING
|
||
|
* context_bad recolormark noeat
|
||
|
.else
|
||
|
* context_ws noeat
|
||
|
.endif
|
||
|
|
||
|
# We encountered a valid context.
|
||
|
:context_color Keyword
|
||
|
* context_ws noeat
|
||
|
|
||
|
# We saw something that is not a valid context name with checking enabled.
|
||
|
# Continue to highlight it as Bad until we see whitespace or a comment.
|
||
|
:context_bad Bad
|
||
|
* context_bad
|
||
|
" \t#\n" context_ws noeat
|
||
|
.endif
|
||
|
|
||
|
|
||
|
##############
|
||
|
# Transition #
|
||
|
##############
|
||
|
|
||
|
# A state transition starts with a '*', an '&', or a string.
|
||
|
.ifdef STRINGS
|
||
|
# Transitions must start with a string between "[i]strings" and "done".
|
||
|
.else
|
||
|
# We saw either a '*' or an '&'. Now we need the next state.
|
||
|
:special_character Keyword
|
||
|
* need_next_state noeat
|
||
|
.endif
|
||
|
|
||
|
# We are in a string. Continue until we see the close quote or a newline.
|
||
|
# Highlight escaped characters within the string differently. They start with a
|
||
|
# '\'.
|
||
|
:string String string
|
||
|
* string
|
||
|
"\\" escape recolor=-1
|
||
|
"\"" need_next_state
|
||
|
.ifdef CHECKING
|
||
|
"\n" bad
|
||
|
.else
|
||
|
"\n" bad noeat
|
||
|
.endif
|
||
|
|
||
|
# Highlight an escaped character within a string.
|
||
|
:escape StringEscape string
|
||
|
* string
|
||
|
|
||
|
# Loop over whitespace until we see the first character of the next state.
|
||
|
:need_next_state Idle
|
||
|
* bad noeat
|
||
|
" \t" need_next_state
|
||
|
"\i" next_state recolor=-1
|
||
|
|
||
|
# Now we highlight the remainder of the next state.
|
||
|
:next_state State
|
||
|
* bad noeat
|
||
|
"\c" next_state
|
||
|
" \t" options_ws
|
||
|
"#\n" comment noeat
|
||
|
|
||
|
# Following the next state should be zero or more options. Loop over whitespace
|
||
|
# until we find an option, comment, or newline.
|
||
|
:options_ws Idle
|
||
|
* option_bad recolor=-1
|
||
|
" \t" options_ws
|
||
|
"\i" option mark recolor=-1 buffer
|
||
|
"#\n" comment noeat
|
||
|
|
||
|
# Here we recognize the possible options. The strings and istrings options
|
||
|
# cannot be used between "[i]strings" and "done". Since conditional directives
|
||
|
# cannot be used between "[i]strings" and "done" either, the list must be
|
||
|
# duplicated, once without and once with the strings and istrings options.
|
||
|
:option Idle
|
||
|
.ifdef STRINGS
|
||
|
* option_unknown recolormark noeat strings
|
||
|
"noeat" option_color
|
||
|
"recolor" recolor_color
|
||
|
"mark" option_color
|
||
|
"markend" option_color
|
||
|
"recolormark" option_color
|
||
|
"buffer" option_color
|
||
|
"save_c" option_color
|
||
|
"save_s" option_color
|
||
|
"hold" option_color
|
||
|
"call" call_color
|
||
|
"return" option_color
|
||
|
"reset" option_color
|
||
|
done
|
||
|
.else
|
||
|
* option_unknown recolormark noeat strings
|
||
|
"noeat" option_color
|
||
|
"recolor" recolor_color
|
||
|
"mark" option_color
|
||
|
"markend" option_color
|
||
|
"recolormark" option_color
|
||
|
"buffer" option_color
|
||
|
"save_c" option_color
|
||
|
"save_s" option_color
|
||
|
"strings" strings_color
|
||
|
"istrings" strings_color
|
||
|
"hold" option_color
|
||
|
"call" call_color
|
||
|
"return" option_color
|
||
|
"reset" option_color
|
||
|
done
|
||
|
.endif
|
||
|
"\c" option
|
||
|
|
||
|
# We encountered what looks like an option but is unrecognized as such.
|
||
|
:option_unknown Idle
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws noeat
|
||
|
.endif
|
||
|
|
||
|
# We have encountered an option that does not take an argument. Highlight it
|
||
|
# and continue to look for more options.
|
||
|
:option_color Keyword
|
||
|
* options_ws noeat
|
||
|
|
||
|
.ifdef STRINGS
|
||
|
# The strings and istrings options cannot be used between "[i]strings" and
|
||
|
# "done".
|
||
|
.else
|
||
|
# The strings and istrings options are followed by a list of transitions.
|
||
|
# Rather than duplicate all of the states that highlight transitions, we call
|
||
|
# this entire file as a subroutine and use the STRINGS parameter to disable
|
||
|
# everything else and enable the done keyword. We return to the comment_or_bad
|
||
|
# state since we will return after seeing the done keyword, and nothing but a
|
||
|
# comment should follow the done keyword.
|
||
|
:strings_color Keyword
|
||
|
* comment_or_bad noeat call=jsf(STRINGS)
|
||
|
.endif
|
||
|
|
||
|
# Highlight the recolor option.
|
||
|
:recolor_color Keyword
|
||
|
* recolor_equal noeat
|
||
|
|
||
|
# The recolor option must be followed by an '='. Loop over whitespace until we
|
||
|
# find one.
|
||
|
:recolor_equal Idle
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws noeat
|
||
|
.endif
|
||
|
" \t" recolor_equal
|
||
|
"=" recolor_minus mark
|
||
|
|
||
|
# The recolor option takes an integer argument, and that integer must be
|
||
|
# negative. Thus the '=' must be followed by a minus sign. Loop over
|
||
|
# whitespace until we find one.
|
||
|
:recolor_minus Idle
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws noeat
|
||
|
.endif
|
||
|
" \t" recolor_minus
|
||
|
"-" recolor_amount_first mark recolor=-1
|
||
|
|
||
|
# The first digit of the argument to recolor must be non-zero.
|
||
|
:recolor_amount_first Number
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws recolormark noeat
|
||
|
"0" option_bad recolormark noeat
|
||
|
.endif
|
||
|
"1-9" recolor_amount
|
||
|
|
||
|
# Keep highlighting digits until we see something else.
|
||
|
:recolor_amount Number
|
||
|
* option_bad recolormark recolor=-1
|
||
|
"0-9" recolor_amount
|
||
|
" \t#\n" options_ws noeat
|
||
|
|
||
|
# Highlight the call option.
|
||
|
:call_color Keyword
|
||
|
* call_equal noeat
|
||
|
|
||
|
# The call option must be followed by an '='. Loop over whitespace until we
|
||
|
# find one.
|
||
|
:call_equal Idle
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws noeat
|
||
|
.endif
|
||
|
" \t" call_equal
|
||
|
"=" call_file_or_dot mark
|
||
|
|
||
|
# The first part of the argument to the call option is the name of the file
|
||
|
# containing the subroutine or a '.', implying the current file. Loop over
|
||
|
# whitespace until we see one of those two things.
|
||
|
:call_file_or_dot Idle
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws noeat
|
||
|
.endif
|
||
|
" \t" call_file_or_dot
|
||
|
"\i" call_file mark recolor=-1
|
||
|
"." call_dot mark
|
||
|
|
||
|
# Highlight the remainder of the file name. The file name can be followed by a
|
||
|
# '.', which must then be followed by the name of a subroutine, or by a list of
|
||
|
# parameters in parentheses. The '.', if present, cannot have whitespace on
|
||
|
# either side.
|
||
|
:call_file Subr
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws noeat
|
||
|
.endif
|
||
|
"\c" call_file
|
||
|
"." call_dot mark recolor=-1
|
||
|
" \t(" call_open_paren noeat
|
||
|
|
||
|
# We saw a '.'. The next character must start the name of a subroutine.
|
||
|
:call_dot Idle
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws noeat
|
||
|
.endif
|
||
|
"(" call_dot_bad recolormark noeat
|
||
|
"\i" call_subr mark recolor=-1
|
||
|
|
||
|
# We have seen a dot followed by an open parenthesis. A dot must be followed by
|
||
|
# a subroutine name. Highlight the dot as Bad.
|
||
|
:call_dot_bad Bad
|
||
|
* call_open_paren noeat
|
||
|
|
||
|
# Highlight the remainder of the subroutine name. Following the subroutine name
|
||
|
# must be a list of parameters in parentheses, possibly preceded by whitespace.
|
||
|
:call_subr Subr
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws noeat
|
||
|
.endif
|
||
|
"\c" call_subr
|
||
|
" \t(" call_open_paren noeat
|
||
|
|
||
|
# Loop over whitespace until we find the open parenthesis.
|
||
|
:call_open_paren Idle
|
||
|
.ifdef CHECKING
|
||
|
* option_bad recolormark noeat
|
||
|
.else
|
||
|
* options_ws noeat
|
||
|
.endif
|
||
|
" \t" call_open_paren
|
||
|
"(" call_parameters_ws
|
||
|
|
||
|
# The list of parameters is delimited by whitespace. Loop over whitespace until
|
||
|
# we find either the beginning of a parameter or a close parenthesis. We should
|
||
|
# not see a comment or newline since the list should be terminated by a close
|
||
|
# parenthesis.
|
||
|
:call_parameters_ws Idle
|
||
|
* call_parameter_bad recolor=-1
|
||
|
" \t" call_parameters_ws
|
||
|
"-" call_parameter_undef
|
||
|
"\i" call_parameter recolor=-1
|
||
|
")" options_ws
|
||
|
"#\n" bad noeat
|
||
|
|
||
|
# We saw a "-". The next character should start the parameter being undefined.
|
||
|
:call_parameter_undef Parameter
|
||
|
* call_parameters_ws noeat
|
||
|
"\i" call_parameter recolor=-2
|
||
|
|
||
|
# Highlight the remainder of the parameter.
|
||
|
:call_parameter Parameter
|
||
|
* call_parameters_ws noeat
|
||
|
"\c" call_parameter
|
||
|
|
||
|
# We saw something that is not a valid parameter name. Continue to highlight it
|
||
|
# as Bad until we see whitespace.
|
||
|
:call_parameter_bad Bad
|
||
|
* call_parameter_bad
|
||
|
") \t#\n" call_parameters_ws noeat
|
||
|
|
||
|
# We saw something that is not a valid option name. Continue to highlight it as
|
||
|
# Bad until we see whitespace or a comment.
|
||
|
:option_bad Bad
|
||
|
* option_bad
|
||
|
" \t#\n" options_ws noeat
|
||
|
|
||
|
|
||
|
########
|
||
|
# Done #
|
||
|
########
|
||
|
|
||
|
.ifdef STRINGS
|
||
|
# The special word, "done", can only be used after a strings or istrings option.
|
||
|
# Recognize the done keyword.
|
||
|
:special_word Idle
|
||
|
* bad_line recolormark noeat strings
|
||
|
"done" done_color
|
||
|
done
|
||
|
"\c" special_word
|
||
|
|
||
|
# Highlight the done keyword and return to highlighting things normally, since
|
||
|
# the list of strings has been terminated.
|
||
|
:done_color Keyword
|
||
|
* comment_or_bad return noeat
|
||
|
.endif
|
||
|
|
||
|
|
||
|
##################
|
||
|
# Comment or Bad #
|
||
|
##################
|
||
|
|
||
|
# We have seen everything that should appear on the current line except an
|
||
|
# optional comment. Loop over whitespace until we find a comment or newline.
|
||
|
:comment_or_bad Idle
|
||
|
* bad noeat
|
||
|
" \t" comment_or_bad
|
||
|
"#\n" comment noeat
|
||
|
|
||
|
|
||
|
###########
|
||
|
# Comment #
|
||
|
###########
|
||
|
|
||
|
# Continue to highlight the comment until the end of the line.
|
||
|
:comment Comment comment
|
||
|
* comment
|
||
|
"BFHNTX" comment noeat call=comment_todo.comment_todo()
|
||
|
"\n" idle
|
||
|
|
||
|
|
||
|
#######
|
||
|
# Bad #
|
||
|
#######
|
||
|
|
||
|
.ifdef CHECKING
|
||
|
# We have encountered incorrect syntax. Loop over whitespace until we see the
|
||
|
# first visible character. Highlight that character and the rest of the line as
|
||
|
# Bad.
|
||
|
:bad Bad
|
||
|
* bad_line
|
||
|
" \t\n" bad
|
||
|
.else
|
||
|
# When not performing strict checking, don't go searching for the next visible
|
||
|
# character to highlight as Bad. Simply highlight the rest of the line as Bad,
|
||
|
# even if it is invisible.
|
||
|
:bad Bad
|
||
|
* bad_line noeat
|
||
|
.endif
|
||
|
|
||
|
# Continue to highlight everything as Bad until the end of the line.
|
||
|
:bad_line Bad
|
||
|
* bad_line
|
||
|
"\n" idle
|