summaryrefslogtreecommitdiff
path: root/src/cgil/ragel.lm
diff options
context:
space:
mode:
Diffstat (limited to 'src/cgil/ragel.lm')
-rw-r--r--src/cgil/ragel.lm1027
1 files changed, 1027 insertions, 0 deletions
diff --git a/src/cgil/ragel.lm b/src/cgil/ragel.lm
new file mode 100644
index 00000000..1325bbb3
--- /dev/null
+++ b/src/cgil/ragel.lm
@@ -0,0 +1,1027 @@
+
+global GblActionParams: bool = false
+global GblMachineMap: map<str, machine> = new map<str, machine>()
+global GblCurMachine: machine
+global GblTargetMachine: str = ""
+global GblSearchMachine: str = ""
+global GblWantSection: bool = false
+global GblIncludeDepth: int = 0
+global GblImport: bool = false
+global GblFileName: str = ""
+global GblIncludePaths: list<str> = new list<str>()
+
+struct saved_globals
+ FileName: str
+ TargetMachine: str
+ SearchMachine: str
+ WantSection: bool
+ IncludeDepth: int
+ Import: bool
+end
+
+global GblSavedGlobals: list<saved_globals> = new list<saved_globals>()
+
+void saveGlobals()
+{
+ new SG: saved_globals()
+
+ SG->FileName = GblFileName
+ SG->TargetMachine = GblTargetMachine
+ SG->SearchMachine = GblSearchMachine
+ SG->WantSection = GblWantSection
+ SG->Import = GblImport
+ SG->IncludeDepth = GblIncludeDepth
+
+ GblSavedGlobals->push_tail( SG )
+}
+
+void restoreGlobals()
+{
+ SG: saved_globals = GblSavedGlobals->pop_tail()
+
+ GblFileName = SG->FileName
+ GblTargetMachine = SG->TargetMachine
+ GblSearchMachine = SG->SearchMachine
+ GblWantSection = SG->WantSection
+ GblImport = SG->Import
+ GblIncludeDepth = SG->IncludeDepth
+}
+
+struct include_history_item
+ FileName: str
+ SectionName: str
+end
+
+bool isDuplicateInclude( From: machine, FileName: str, SectionName: str )
+{
+ for Item: include_history_item in From->IncludeHistory {
+ if Item->FileName == FileName && Item->SectionName == SectionName {
+ return true
+ }
+ }
+ return false
+}
+
+void addIncludeItem( From: machine, FileName: str, SectionName: str )
+{
+ new Item: include_history_item()
+ Item->FileName = FileName
+ Item->SectionName = SectionName
+ From->IncludeHistory->push_tail( Item )
+}
+
+struct machine
+ Name: str
+ ActionParams: map<str, str>
+ IncludeHistory: list<include_history_item>
+end
+
+
+rl ident
+ /( alpha | '_' ) ( alpha | digit | '_' )*/
+
+rl number
+ / digit+ /
+
+rl hex_number
+ / '0x' [0-9a-fA-F]+ /
+
+rl hex_char
+ / '0x' [0-9a-fA-F]{2} /
+
+rl NL / '\n' /
+
+rl c_comment
+ / '/*' ( any | NL )* :>> '*/' /
+
+rl cpp_comment
+ / '//' [^\n]* NL /
+
+rl ruby_comment
+ / '#' [^\n]* NL /
+
+rl s_literal
+ / "'" ([^'\\\n] | '\\' (any | NL))* "'" /
+
+rl d_literal
+ / '"' ([^"\\] | NL | '\\' (any | NL))* '"' /
+
+rl host_re_literal
+ / '/' ([^/\\] | NL | '\\' (any | NL))* '/' /
+
+#
+# Consuming ragel defintions without parsing. Used for included sections we
+# don't want and for import (TODO).
+#
+namespace consume
+ lex
+ token h_word / [a-zA-Z_][a-zA-Z0-9_]* /
+
+ token h_open /'{'/
+ token h_close /'}'/
+
+ token h_number /digit+/
+ token h_hex_number /'0x' [0-9a-fA-F]+/
+
+ token h_comment
+ / c_comment | cpp_comment /
+
+ token h_string
+ / s_literal | d_literal /
+
+ token h_whitespace
+ / ( [ \t] | NL )+ /
+
+ token h_any / any /
+ end
+
+ def host_tok
+ [h_word]
+ | [h_number]
+ | [h_hex_number]
+ | [h_comment]
+ | [h_string]
+ | [h_whitespace]
+ | [h_open host_tok* h_close]
+ | [h_any]
+
+ lex
+ ignore /[\t\n ]+/
+ ignore /'#' any* :> '\n'/
+
+ literal `}%%
+
+ token word / [a-zA-Z_][a-zA-Z0-9_]* /
+ token uint / number /
+ token hex / hex_number /
+
+ token string /
+ '"' ( [^"\\] | '\\' any )* '"' 'i'? |
+ "'" ( [^'\\] | '\\' any )* "'" 'i'? |
+ "[" ( [^\]\\] | '\\' any )* "]" 'i'? #|
+ #"/" ( [^\/\\] | '\\' any )* "/" 'i'?
+ /
+
+
+ token open /'{'/ -ni
+ token close ni- /'}'/
+ token c_any / any /
+ end
+
+
+ # Garbling up a machine, no interpretation
+ def tok
+ [word]
+ | [uint]
+ | [hex]
+ | [string]
+ | [open host_tok* h_close]
+ | [c_any]
+end
+
+# State reference.
+namespace state_ref
+ lex
+ ignore /[\t\n ]+/
+ literal `:: `; `)
+ token word /[a-zA-Z_][a-zA-Z0-9_]*/
+ end
+
+ def state_ref
+ [opt_name_sep state_ref_names] :Ref
+
+ def opt_name_sep
+ [`::] :ColonColon
+ | [] :Empty
+
+ # List of names separated by ::
+ def state_ref_names
+ [state_ref_names `:: word] :Rec
+ | [word] :Base
+end
+
+namespace inline
+
+ def inline_expr
+ [expr_item_list] :List
+
+ def expr_item_list
+ [expr_item_list expr_item] :Rec
+ | [] :Empty
+
+ def expr_item
+ [expr_any] :ExprAny
+ | [expr_symbol] :ExprSymbol
+ | [expr_interpret] :ExprInterpret
+
+ def expr_any
+ [whitespace] :WS
+ | [comment] :Comment
+ | [string] :String
+ | [number] :Number
+ | [hex_number] :Hex
+ | [ident] :Ident
+ | [c_any] :Any
+
+ def expr_symbol
+ [`,] :Comma | [`(] :Open | [`)] :Close | [`*] :Star | [`::] :DoubleColon
+
+ def expr_interpret
+ [`fpc] :Fpc
+ | [`fc] :Fc
+ | [`fcurs] :Fcurs
+ | [`ftargs] :Ftargs
+ | [`fentry `( state_ref::state_ref state_ref::`)] :Fentry
+ | [var_ref] :VarRef
+
+ def inline_block
+ [block_item_list] :List
+
+ def block_item_list
+ [block_item block_item_list] :Rec
+ | [] :Base
+
+ def block_item
+ [expr_any] :ExprAny
+ | [block_symbol] :BlockSymbol
+ | [block_interpret] :BlockInterpret
+ | [`{ inline_block `}] :RecBlock
+
+ def block_symbol
+ [`,] :B1 | [`;] :B2 | [`(] :B3 | [`)] :B4 | [`*] :B5 | [`::] :B6
+
+ def block_interpret
+ [expr_interpret] :ExprInterpret
+ | [`fhold whitespace? `;] :Fhold
+ | [`fgoto whitespace? `* inline_expr `;] :FgotoExpr
+ | [`fnext whitespace? `* inline_expr `;] :FnextExpr
+ | [`fcall whitespace? `* inline_expr `;] :FcallExpr
+ | [`fncall whitespace? `* inline_expr `;] :FncallExpr
+ | [`fexec inline_expr `;] :Fexec
+ | [`fgoto state_ref::state_ref state_ref::`;] :FgotoSr
+ | [`fnext state_ref::state_ref state_ref::`;] :FnextSr
+ | [`fcall state_ref::state_ref state_ref::`;] :FcallSr
+ | [`fncall state_ref::state_ref state_ref::`;] :FncallSr
+ | [`fret `;] :Fret
+ | [`fnret `;] :Fnret
+ | [`fbreak `;] :Fbreak
+ | [`fnbreak `;] :Fnbreak
+end
+
+namespace ragel
+ lex
+ literal `}%% -ni
+
+ ignore /[\t\n ]+/
+ ignore /'#' any* :> '\n'/
+
+ literal `^ `| `- `, `: `! `? `.
+ literal `( `) `{ -ni ni- `} `* `& `+
+
+ literal `-- `:> `:>> `<: `-> `**
+
+ literal `|* `*| `=>
+
+ literal `@ `> `< `% `$
+ literal `from `to `eof `lerr `err
+ literal `when `inwhen `outwhen `>? `$? `%?
+
+ literal `:= `|= `= `; `.. `../i `::
+
+ literal `>~ `$~ `%~ `<~ `@~ `<>~
+ literal `>* `$* `%* `<* `@* `<>*
+ literal `>/ `$/ `%/ `</ `@/ `<>/
+ literal `>! `$! `%! `<! `@! `<>!
+ literal `>^ `$^ `%^ `<^ `@^ `<>^
+ literal `<>
+
+ literal `%%--{ -ni `%%++{ -ni
+
+ token include_tok
+ /'include'/
+ {
+ # Take off the include token.
+ input->pull( match_length )
+
+ # Parse the include details, up to the the ';' and stop there.
+ parse_stop Spec: include_spec(input)[]
+
+ Fn: str
+ Machine: str
+ if Spec.string
+ Fn = $Spec.string
+ if Spec.word
+ Machine = $Spec.word
+
+ Stream: stream = ragelInclude( Fn, Machine )
+
+ if Stream {
+ input->push( "}--%%" )
+ input->push_stream( Stream )
+ input->push( "%%--{" )
+ }
+ }
+
+ token import_tok
+ /'import'/
+ {
+ # Take off the include token.
+ input->pull( match_length )
+
+ # Parse the import details, up to the the ';' and stop there.
+ parse_stop Spec: import_spec(input)[]
+
+ Fn: str
+ if Spec.string
+ Fn = $Spec.string
+
+ Stream: stream = ragelImport( Fn )
+
+ if Stream {
+ input->push( "}++%%" )
+ input->push_stream( Stream )
+ input->push( "%%++{" )
+ }
+ }
+
+
+ literal `machine `action `variable `alphtype
+ `access `write `getkey `export `prepush
+ `postpop `nfaprepush `nfapostpop
+
+ literal `:nfa `:nfa_greedy `:nfa_lazy `:nfa_wrap
+ `:nfa_wrap_greedy `:nfa_wrap_lazy
+ `:cond `:condplus `:condstar `):
+
+ token string /
+ '"' ( [^"\\] | '\\' any )* '"' 'i'? |
+ "'" ( [^'\\] | '\\' any )* "'" 'i'?
+ /
+
+ token lex_regex_open /'/'/ -ni
+ token lex_sqopen_pos /'['/ -ni
+ token lex_sqopen_neg /'[^'/ -ni
+
+ token word / [a-zA-Z_][a-zA-Z0-9_]* /
+ token uint / number /
+ token hex / hex_number /
+ end
+
+ def include_spec
+ [word `;]
+ | [string `;]
+ | [word string `;]
+
+ def import_spec
+ [string `;]
+
+ lex
+ token re_dot / '.' /
+ token re_star / '*' /
+ token re_char / ^( '\\' | '.' | '*' | '[' | '/' ) | '\\' . any /
+ token re_close / '/' 'i'? /
+ token re_sqopen_pos /'['/
+ token re_sqopen_neg /'[^'/
+ end
+
+ lex
+ token re_or_dash / '-' /
+ token re_or_char / ^( '\\' | '-' | ']' ) | '\\' . any /
+ token re_or_sqclose / ']' /
+ end
+
+ # Not cannot start with '{', terminated by ';', rewritten into { inline_expr }
+ token _inline_expr_reparse
+ /[^{;] [^;]* ';'/ {
+ R: str = input->pull( match_length - 1 )
+ input->pull( 1 )
+ input->push( "}" )
+ input->push( R )
+ input->push( "{" )
+ }
+
+ token variable_name /ident/
+
+ # This region is for deciding if we want to parse a ragel section, or if we
+ # want to consume it without interpreting. Consuming is for included
+ # sections we don't want and all sections in an imported file.
+ lex
+ token ign_select /''/
+ {
+ if GblWantSection
+ input->push( make_token( typeid<ign_want>, '' ) )
+ else
+ input->push( make_token( typeid<ign_ignore>, '' ) )
+ }
+
+ token ign_want //
+ token ign_ignore //
+ end
+
+ #
+ # Machine name word. We inspect it to determine if we are interested in the
+ # section.
+ #
+ lex
+ token mn_word / [a-zA-Z_][a-zA-Z0-9_]* /
+ {
+ S: str = input->pull(match_length)
+ IgnWord: mn_word = make_token( typeid<mn_word>, S )
+ input->push( IgnWord )
+
+ if ( GblImport )
+ GblWantSection = false
+ else if ( GblSearchMachine != "" ) {
+ if ( S != GblSearchMachine )
+ GblWantSection = false
+ else
+ GblWantSection = true
+ }
+ else {
+ GblWantSection = true
+ }
+
+ Name: str = S #$lhs.mn_word
+ if GblTargetMachine != ""
+ Name = GblTargetMachine
+
+ Machine: machine = GblMachineMap->find( Name )
+
+ if !Machine
+ {
+ Machine = new machine()
+ Machine->Name = Name
+ Machine->ActionParams = new map<str, str>()
+ Machine->IncludeHistory = new list<include_history_item>()
+ GblMachineMap->insert( Machine->Name, Machine )
+ }
+
+ GblCurMachine = Machine
+
+ # print "want section: [GblWantSection]
+ }
+ end
+
+
+ def inline_expr_reparse
+ [_inline_expr_reparse] :Reparse
+ | [action_expr] :ActionExpr
+
+ def join
+ [join `, expression] :Rec
+ | [expression] :Base
+
+ def expression
+ [expr_left expression_op_list] :Expression
+
+ def expression_op_list
+ [expression_op expression_op_list] :Op
+ | [] :Empty
+
+ def expression_op
+ [`| term] :Or
+ | [`& term] :And
+ | [`- term] :Sub
+ | [`-- term] :Ssub
+
+ def expr_left
+ [term] :Term
+
+ def term
+ [term_left term_op_list_short] :Term
+
+ def term_left
+ [factor_label] :FactorLabel
+
+ # This list is done manually to get shortest match.
+ def term_op_list_short
+ [] :Empty
+ | [term_op term_op_list_short] :Terms
+
+ def term_op
+ [factor_label] :None
+ | [`. factor_label] :Dot
+ | [`:> factor_label] :ColonLt
+ | [`:>> factor_label] :ColonLtLt
+ | [`<: factor_label] :GtColon
+
+ def factor_label
+ [word `: factor_label] :Label
+ | [factor_ep] :Ep
+
+ def factor_ep
+ [factor_aug `-> epsilon_target] :Epsilon
+ | [factor_aug] :Base
+
+ def epsilon_target
+ [epsilon_target `:: word] :Rec
+ | [word] :Base
+
+ def action_expr
+ [`{ CInlineExpr: inline::inline_expr inline::`}] :ActionExpr
+
+ def action_block
+ [`{ CInlineBlock: inline::inline_block inline::`}] :ActionBlock
+
+ def action_arg_list
+ [action_arg_list `, action_ref] :Rec
+ | [action_ref] :Base
+
+ def opt_action_arg_list
+ [action_arg_list] :List
+ | [] :Empty
+
+ def named_action_ref
+ [word] :Plain
+ {
+ if ( GblCurMachine->ActionParams->find( $lhs.word ) )
+ reject
+ }
+ | [word `( opt_action_arg_list `)] :Args
+ {
+ if ( ! GblCurMachine->ActionParams->find( $lhs.word ) )
+ reject
+ }
+
+ def action_ref
+ [named_action_ref] :NamedRef
+ | [`( named_action_ref `)] :ParenNamed
+ | [action_block] :Block
+
+ def priority_name
+ [word] :Word
+
+ def error_name
+ [word] :Word
+
+ def priority_aug
+ [uint] :NoSign
+ | [`+ uint] :Plus
+ | [`- uint] :Minus
+
+ def aug_base
+ [`@] :Finish | [`>] :Enter | [`%] :Leave | [`$] :All
+
+ def aug_cond
+ [`>?] :Start1 | [`$?] :All1 | [`%?] :Leave1
+ | [`> `when] :Start2 | [`$ `when] :All2 | [`% `when] :Leave2
+ | [`inwhen] :Start3 | [`when] :All3 | [`outwhen] :Leave3
+
+ def aug_to_state
+ [`>~] :Start1 | [`<~] :NotStart1 | [`$~] :All1
+ | [`%~] :Final1 | [`@~] :NotFinal1 | [`<>~] :Middle1
+ | [`> `to] :Start2 | [`< `to] :NotStart2 | [`$ `to] :All2
+ | [`% `to] :Final2 | [`@ `to] :NotFinal2 | [`<> `to] :Middle2
+
+ def aug_from_state
+ [`>*] :Start1 | [`<*] :NotStart1 | [`$*] :All1
+ | [`%*] :Final1 | [`@*] :NotFinal1 | [`<>*] :Middle1
+ | [`> `from] :Start2 | [`< `from] :NotStart2 | [`$ `from] :All2
+ | [`% `from] :Final2 | [`@ `from] :NotFinal2 | [`<> `from] :Middle2
+
+ def aug_eof
+ [`>/] :Start1 | [`</] :NotStart1 | [`$/] :All1
+ | [`%/] :Final1 | [`@/] :NotFinal1 | [`<>/] :Middle1
+ | [`> `eof] :Start2 | [`< `eof] :NotStart2 | [`$ `eof] :All2
+ | [`% `eof] :Final2 | [`@ `eof] :NotFinal2 | [`<> `eof] :Middle2
+
+ def aug_gbl_error
+ [`>!] :Start1 | [`<!] :NotStart1 | [`$!] :All1
+ | [`%!] :Final1 | [`@!] :NotFinal1 | [`<>!] :Middle1
+ | [`> `err] :Start2 | [`< `err] :NotStart2 | [`$ `err] :All2
+ | [`% `err] :Final2 | [`@ `err] :NotFinal2 | [`<> `err] :Middle2
+
+ def aug_local_error
+ [`>^] :Start1 | [`<^] :NotStart1 | [`$^] :All1
+ | [`%^] :Final1 | [`@^] :NotFinal1 | [`<>^] :Middle1
+ | [`> `lerr] :Start2 | [`< `lerr] :NotStart2 | [`$ `lerr] :All2
+ | [`% `lerr] :Final2 | [`@ `lerr] :NotFinal2 | [`<> `lerr] :Middle2
+
+ def factor_aug
+ [factor_aug aug_base action_ref] :ActionRef
+ | [factor_aug aug_base priority_aug] :PriorEmbed
+ | [factor_aug aug_base `( priority_name `, priority_aug `)] :NamedPriorEmbed
+ | [factor_aug aug_cond action_ref] :CondEmbed
+ | [factor_aug aug_cond `! action_ref] :NegCondEmbed
+ | [factor_aug aug_to_state action_ref] :ToStateAction
+ | [factor_aug aug_from_state action_ref] :FromStateAction
+ | [factor_aug aug_eof action_ref] :EofAction
+ | [factor_aug aug_gbl_error action_ref] :GblErrorAction
+ | [factor_aug aug_local_error action_ref] :LocalErrorDef
+ | [factor_aug aug_local_error `( error_name `, action_ref `)] :LocalErrorName
+ | [factor_rep] :Base
+
+ def factor_rep
+ [factor_neg factor_rep_op_list] :Op
+
+ def factor_rep_op_list
+ [factor_rep_op factor_rep_op_list] :Rec
+ | [] :Base
+
+ def factor_rep_op
+ [`*] :Star
+ | [`**] :StarStar
+ | [`?] :Optional
+ | [`+] :Plus
+ | [`{ factor_rep_num `}] :ExactRep
+ | [`{ `, factor_rep_num `}] :MaxRep
+ | [`{ factor_rep_num `, `}] :MinRep
+ | [`{ LowRep: factor_rep_num `, HighRep: factor_rep_num `}] :RangeRep
+
+ def factor_rep_num
+ [uint] :RepNum
+
+ def factor_neg
+ [`! factor_neg] :Bang
+ | [`^ factor_neg] :Caret
+ | [factor] :Base
+
+ def opt_max_arg
+ [`, action_ref] :Action
+ | [] :Empty
+
+ def nfastar
+ [`:nfa] :Default
+ | [`:nfa_lazy] :Lazy
+ | [`:nfa_greedy] :Greedy
+
+ def nfawrap
+ [`:nfa_wrap] :Default
+ | [`:nfa_wrap_lazy] :Lazy
+ | [`:nfa_wrap_greedy] :Greedy
+
+ def colon_cond
+ [`:cond] :Cond
+ | [`:condstar] :CondStar
+ | [`:condplus] :CondPlus
+
+ def factor
+ [alphabet_num] :AlphabetNum
+ | [word] :Word
+ | [string] :String
+ | [lex_sqopen_pos reg_or_data re_or_sqclose] :PosOrBlock
+ | [lex_sqopen_neg reg_or_data re_or_sqclose] :NegOrBlock
+ | [lex_regex_open regex re_close] :Regex
+ | [RL1: range_lit `.. RL2: range_lit] :Range
+ | [RL1: range_lit `../i RL2: range_lit] :RangeIndep
+ | [nfastar `( expression `,
+ Push: action_ref `, Pop: action_ref `, Init: action_ref `, Stay: action_ref `,
+ Repeat: action_ref `, Exit: action_ref `):] :Nfa
+ | [nfawrap `( expression `,
+ Push: action_ref `, Pop: action_ref `, Init: action_ref `, Stay: action_ref `,
+ Exit: action_ref `):] :NfaWrap
+ | [colon_cond `( expression `,
+ Init: action_ref `, Inc: action_ref `, Min: action_ref OptMax: opt_max_arg `):] :Cond
+ | [`( join `)] :Join
+
+ def regex
+ [reg_item_rep_list] :List
+
+ def reg_item_rep_list
+ [reg_item_rep_list reg_item_rep] :Rec
+ | [] :Base
+
+ def reg_item_rep
+ [reg_item re_star] :Star
+ | [reg_item] :Base
+
+ def reg_item
+ [re_sqopen_pos reg_or_data re_or_sqclose] :PosOrBlock
+ | [re_sqopen_neg reg_or_data re_or_sqclose] :NegOrBlock
+ | [re_dot] :Dot
+ | [re_char] :Char
+
+ def reg_or_data
+ [reg_or_data reg_or_char] :Data
+ | [] :Base
+
+ def reg_or_char
+ [re_or_char] :Char
+ | [Low: re_or_char re_or_dash High: re_or_char] :Range
+
+ def range_lit
+ [string] :String
+ | [alphabet_num] :AN
+
+ def alphabet_num
+ [uint] :Uint
+ | [`- uint] :Neg
+ | [hex] :Hex
+
+ def lm_act
+ [`=> action_ref] :ActionRef
+ | [action_block] :ActionBlock
+
+ def opt_lm_act
+ [lm_act] :Act
+ | [] :Empty
+
+ def lm_stmt
+ [join opt_lm_act `;] :LmStmt commit
+ | [assignment] :Assignment
+ | [action_spec] :ActionSpec
+
+ def lm_stmt_list
+ [lm_stmt_list lm_stmt] :Rec
+ | [lm_stmt] :Base
+
+ def lm
+ [join] :Join
+ | [`|* lm_stmt_list `*|] :Lm
+ | [`:nfa `|* lm_stmt_list `*|] :LmNfa
+
+ #
+ # Actions
+ #
+ def action_param
+ [word] :Word
+
+ def action_param_list
+ [action_param_list `, action_param] :Rec
+ | [action_param] :Base
+
+ def opt_action_param_list
+ [action_param_list] :List
+ | [] :Empty
+
+ def action_params
+ [`( opt_action_param_list `)] :List
+ {
+ GblActionParams = true
+ }
+
+ def action_spec
+ [`action word action_params action_block] :ActionSpecParams commit
+ {
+ # Track that this action has params so we can parse appropriately
+ # when reducing.
+ GblCurMachine->ActionParams->insert( $lhs.word, $lhs.word )
+
+ # Reset after parsing the block.
+ GblActionParams = false
+ }
+ | [`action word action_block] :ActionSpec commit
+ {
+ GblActionParams = false
+ }
+
+ def def_name
+ [word] :Word
+
+ #
+ # Machine Instantiations.
+ #
+ def assignment
+ [opt_export def_name `= join `;] :Assignment commit
+
+ def instantiation
+ [opt_export def_name `:= lm `;] :Instantiation commit
+
+ def nfa_expr
+ [nfa_expr `| term] :Union
+ | [term] :Base
+
+ def nfa_round_spec
+ [Depth: uint `, Group: uint] :Spec
+
+ def nfa_round_list
+ [nfa_round_list `, nfa_round_spec] :Recurse
+ | [nfa_round_spec] :Base
+
+ def nfa_rounds
+ [`( nfa_round_list `)] :Rounds
+
+ def nfa_union
+ [def_name `|= nfa_rounds nfa_expr `;] :NfaUnion commit
+
+ def alphtype_type
+ [W1: word] :One
+ | [W1: word W2: word] :Two
+
+ def opt_export
+ [`export] :Export
+ | [] :Base
+
+ def write_arg
+ [word] :Word
+
+ def machine_name
+ [`machine mn_word `;] :MachineName
+
+ def open_inc
+ [`%%--{] :OpenInc
+
+ def close_inc
+ [host::close_inc] :CloseInc
+
+ def include_statement
+ [open_inc host::section* close_inc] :IncPost commit
+
+ def open_imp
+ [`%%++{] :OpenImp
+
+ def close_imp
+ [host::close_imp] :CloseImp
+
+ def import_statement
+ [open_imp host::section* close_imp] :ImpPost commit
+
+ def statement
+ [assignment] :Assignment
+ | [instantiation] :Instantiation
+ | [nfa_union] :NfaUnion
+ | [action_spec] :ActionSpec
+ | [`prepush action_block] :PrePush commit
+ | [`postpop action_block] :PostPop commit
+ | [`variable variable_name inline_expr_reparse] :Variable commit
+ | [`alphtype alphtype_type `;] :AlphType commit
+ | [`access inline_expr_reparse] :Access commit
+ | [`write Cmd: word ArgList: write_arg* `;] :Write commit
+ | [`getkey inline_expr_reparse] :GetKey commit
+ | [import_statement] :Import commit
+ | [include_statement] :Include commit
+ | [`nfaprepush action_block] :NfaPrePush commit
+ | [`nfapostpop action_block] :NfaPostPop commit
+
+ def opt_machine_name
+ [machine_name] :MachineName
+ | [] :Empty
+
+ def ragel_start
+ [opt_machine_name ign_want statement*]
+ | [opt_machine_name ign_ignore consume::tok*]
+end
+
+str prepareLitString( Str: str )
+{
+ # TODO: escape sequences
+ return suffix( prefix( Str, Str.length - 1 ), 1 )
+}
+
+bool isAbsolutePath( Path: str )
+{
+ # TODO: implement this
+ return false
+}
+
+namespace path
+ lex
+ token slash /'/'/
+ token chars /[^\/]+/
+ end
+
+ def path
+ [Abs: slash? DirList: dir* File: chars]
+
+ def dir
+ [chars slash]
+
+ dir *concat_dir( Dir1: dir*, Dir2: dir* )
+ {
+ for D: dir* in Dir1 {
+ if match D [] {
+ D = Dir2
+ break
+ }
+ }
+ return Dir1
+ }
+end
+
+namespace host
+ token bom / 0xEF 0xBB 0xBF /
+
+ def opt_bom
+ [bom] :Bom
+ | []
+
+ def section
+ [`%%{ ragel::opt_machine_name ragel::ign_want ragel::statement* ragel::`}%%] :MultiLine
+ | [`%%{ ragel::opt_machine_name ragel::ign_ignore consume::tok* consume::`}%%] :Consume
+ | [tok] :Token
+end
+
+def start
+ [host::opt_bom SectionList: host::section*]
+
+list<str> makeIncludePathChecks( CurFileName: str, IncFileName: str )
+{
+ new L: list<str>()
+
+ parse CurPath: path::path[ CurFileName ]
+ parse IncPath: path::path[ IncFileName ]
+
+ if match IncPath.Abs [slash] {
+ # Included file is absolute
+ L->push_tail( IncFileName )
+ }
+ else {
+ # First add the location of current file
+ if match CurPath.DirList []
+ L->push_tail( IncFileName )
+ else {
+ # Current file path + Include Path + Include File
+ cons NewPath: path::path [
+ CurPath.Abs
+ path::concat_dir( CurPath.DirList, IncPath.DirList )
+ IncPath.File
+ ]
+
+ L->push_tail( $NewPath )
+ }
+
+ # Next add include file locations.
+ for Path: str in GblIncludePaths {
+ parse IncPath: path::path[ CurFileName ]
+ L->push_tail( "[Path]/[IncFileName]" )
+ }
+ }
+ return L
+}
+
+stream ragelInclude( IncFileName: str, Machine: str )
+{
+ if IncFileName
+ IncFileName = prepareLitString( IncFileName )
+
+ Checks: list<str>
+ if IncFileName
+ Checks = makeIncludePathChecks( GblFileName, IncFileName )
+ else {
+ Checks = new list<str>()
+ Checks->push_tail( GblFileName )
+
+ }
+
+ Stream: stream
+ OpenedName: str
+ for P: str in Checks {
+ Stream = open( P, "r" )
+ if Stream {
+ OpenedName = P
+ break
+ }
+ }
+
+ if !Stream {
+ print "error: could not open [IncFileName]
+ return nil
+ }
+
+ # Default to the current machine if none is specified.
+ if !Machine
+ Machine = GblCurMachine->Name
+
+ if isDuplicateInclude( GblCurMachine, IncFileName, Machine )
+ return nil
+
+ addIncludeItem( GblCurMachine, IncFileName, Machine )
+
+ saveGlobals()
+
+ GblIncludeDepth = GblIncludeDepth + 1
+ GblFileName = OpenedName
+
+ # Set up the search and target machine names. Search is the machine we want
+ # to include and target is the machine we include to.
+ GblSearchMachine = Machine
+ GblTargetMachine = GblCurMachine->Name
+
+ return Stream
+}
+
+stream ragelImport( IncFileName: str )
+{
+ if IncFileName
+ IncFileName = prepareLitString( IncFileName )
+
+ Checks: list<str>
+ if IncFileName
+ Checks = makeIncludePathChecks( GblFileName, IncFileName )
+ else {
+ Checks = new list<str>()
+ Checks->push_tail( GblFileName )
+ }
+
+ Stream: stream
+ OpenedName: str
+ for P: str in Checks {
+ Stream = open( P, "r" )
+ if Stream {
+ OpenedName = P
+ break
+ }
+ }
+
+ if !Stream {
+ print "error: could not open [IncFileName]
+ return nil
+ }
+
+ saveGlobals()
+
+ GblFileName = OpenedName
+ GblImport = true
+
+ return Stream
+}