-
Notifications
You must be signed in to change notification settings - Fork 2
/
parser.cfg
108 lines (81 loc) · 6.02 KB
/
parser.cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// # A parser template
// # with shift and reduce functionality
exec blubvm/vmx86.cfg
set %parser::stack 0
set %parser::token ""
set %parser::type ""
set %parser::expr ""
set %parser::types ""
set %parser::rstack 0
set %parser::stack 0
// # when there's no rule found and there are too many tokens already
// # error out
set %parser::max_rule_length 10
// # utility functions
alias util::fetch "\"alias\" @_tmp \"set $2 $${${1 asis}}\"; @_tmp; unalias @_tmp"
alias util::append "\"alias\" @_tmp \"set $1 \\\"$${${1 asis}} $2\\\"\"; @_tmp; unalias @_tmp"
alias util::attach "\"alias\" @_tmp \"set $1 \\\"$${${1 asis}}$2\\\"\"; @_tmp; unalias @_tmp"
alias util::set "\"alias\" @_tmp \"set $1 $${${2 asis}}\"; @_tmp; unalias @_tmp"
// # action(action, params...), does not unalias the @_tmp
alias util::action "\"alias\" @_tmp \"$${$1} $${* asis}\"; @_tmp ${2- asis}"
alias util::run "${* asis}"
// # notempty(cvar, target) target = 0 if the cvar doesn't exist or is empty, but won't error when the cvar doesn't exist
// # for that, the RPN is used before the toggle command, and a target cvar is used, target may be the same as the tested cvar
alias util::notempty "menu_cmd rpn \"/$2\" \"/$1\" load def; toggle \"$2\" 1 \"\" 0"
alias util::strcmp "set \"$3\" \"$1\"; toggle \"$3\" 0 \"$2\" 1"
// # sample grammar:
// # ident + ident { eax = @1 + @3; echo $eax }
set %grammar::sample::types[+] addop
set %grammar::sample::types[-] addop
set %grammar::sample::types[*] mulop
set %grammar::sample::types[/] mulop
set %grammar::sample::types[:] end
set %grammar::sample::start "sample[0]"
set %grammar::sample[0]::rules[(ident)] "@sample[0]::ident"
alias @sample[0]::ident "echo ident; parser::push $1; mov eax $1; parser::enter sample[sum]"
set %grammar::sample[1]::rules[(addop)] "@sample[1]::addop"
set %grammar::sample[1]::rules[(mulop)] "@sample[1]::mulop"
alias @sample[1]::addop "echo nextadd; parser::unget $1 addop; parser::enter sample[sum]"
alias @sample[1]::mulop "parser::unget $1 addop; parser::enter sample[sum]; parser::enter sample[mul]"
set %grammar::sample[sum]::rules[(addop)(ident)] "@sample[sum]::addop"
alias @sample[sum]::addop "echo addop; parser::pop eax; menu_cmd rpn /eax eax $2 $1 def; parser::pushv eax; parser::leave; parser::enter sample[1]"
set %grammar::sample[sum]::rules[(mulop)] "@sample[sum]::mulop"
alias @sample[sum]::mulop "parser::enter sample[mul]; parser::unget $1 mulop"
set %grammar::sample[mul]::rules[(mulop)(ident)] "@sample[mul]::mulop"
alias @sample[mul]::mulop "parser::pop eax; menu_cmd rpn /eax eax $2 $1 def; parser::pushv eax; parser::leave; parser::leave; parser::enter sample[1]"
// # set %grammar::sample::rules[(ident)(addop)(ident)] "@sample::addop"
// # alias @sample::addop "( echo ( quote cc $1 + $3 ) )"
// # parsing functions:
// # shifting adds the type to the type list, the token to the expression
// # parser::parse(grammar, expression)
alias @parser::action "${%parser::action} ${* asis}"
alias parser::enter "set %parser::rstack[${%parser::rstack}] \"${%parser::rules}\"; set %parser::rules \"$1\"; inc %parser::rstack"
alias parser::leave "dec %parser::rstack; @parser::leave[2]"
alias @parser::leave[2] "util::fetch \"%parser::rstack[${%parser::stack}]\" %parser::rules"
alias parser::push "set %parser::stack[${%parser::stack}] \"$1\"; inc %parser::stack"
alias parser::pushv "util::fetch $1 %parser::tmp; @parser::pushv[2]"
alias @parser::pushv[2] "@parser::push ${%parser::tmp}"
alias parser::pop "dec %parser::stack; @parser::pop[2] $1"
alias @parser::pop[2] "util::fetch \"%parser::stack[${%parser::stack}]\" $1"
alias parser::unget "set %parser::expr \"${%parser::expr} $1\"; set %parser::types \"${%parser::types}($2)\""
alias parser::parse "set %parser::grammar $1; util::fetch \"%grammar::$1::start\" %parser::rules; @parser::parse ${2- asis} %%EOF%% %%EOF%%"
alias @parser::parse "set %parser::tmp \"$1\"; toggle %parser::tmp @parser::parse[2] \"%%EOF%%\" @parser::eof; util::action %parser::tmp ${* asis}"
alias @parser::parse[2] "set %parser::token \"$1\"; @parser::parse[3] ${2- asis}"
alias @parser::parse[3] "util::notempty \"%grammar::${%parser::grammar}::types[${%parser::token}]\" %parser::tmp; @parser::parse[4] ${* asis}"
alias @parser::parse[4] "toggle %parser::tmp @parser::parse[5a] 0 @parser::parse[5b]; util::action %parser::tmp ${* asis}"
alias @parser::parse[5a] "util::fetch \"%grammar::${%parser::grammar}::types[${%parser::token}]\" %parser::type; @parser::parse[6] ${* asis}"
alias @parser::parse[5b] "set %parser::type ident; @parser::parse[6] ${* asis}"
alias @parser::parse[6] "util::notempty \"%grammar::${%parser::rules}::rules[${%parser::types}(${%parser::type})]\" %parser::tmp; @parser::parse[7] ${* asis}"
alias @parser::parse[7] "toggle %parser::tmp @parser::reduce 0 @parser::shift; util::action %parser::tmp ${* asis}"
// # reduce: apply a rule and keep parsing, by calling @parser::parse
alias @parser::reduce "util::fetch \"%grammar::${%parser::rules}::rules[${%parser::types}(${%parser::type})]\" %parser::tmp; @parser::reduce[2] ${* asis}"
alias @parser::reduce[2] "set %parser::types \"\"; set %parser::expr \"\"; ${%parser::tmp} ${%parser::expr asis} ${%parser::token asis}; @parser::continue ${* asis}"
// # shift: put type and token into types and expr, then keep parsing
alias @parser::shift "set %parser::expr \"${%parser::expr} ${%parser::token}\"; @parser::shift[2] ${* asis}"
alias @parser::shift[2] "set %parser::types \"${%parser::types}(${%parser::type})\"; @parser::continue ${* asis}"
// # clear type and token, then continue parsing
alias @parser::continue "set %parser::type \"\"; set %parser::token \"\"; @parser::parse ${* asis}"
// # on eof, no rule has applied, if types is not empty, print an error
alias @parser::null ""
alias @parser::eof "util::notempty %parser::types %parser::tmp; toggle %parser::tmp @parser::error[tail] 0 @parser::null; util::action %parser::tmp"
alias @parser::error[tail] "echo ^3parse error:^7 expression has no rule: ${%parser::expr}"