Skip to content

Instantly share code, notes, and snippets.

@ysakasin
Last active November 22, 2020 08:49
Show Gist options
  • Save ysakasin/e2b6f3f6d93ee8b0c9dc1a071adf4cda to your computer and use it in GitHub Desktop.
Save ysakasin/e2b6f3f6d93ee8b0c9dc1a071adf4cda to your computer and use it in GitHub Desktop.
# シンタックスハイライトのために .rb にしていますが、このままでは動きません。raccを通す必要があります。
class AddDice
token NUMBER D K H L U R PLUS MINUS ASTERISK SLASH PARENL PARENR LESS GREATER EQUAL NOT
rule
expr: add
| add cmp_op add
{ result = val }
cmp_op: LESS EQUAL
{ result = :<= }
| LESS
{ result = :< }
| GREATER
{ result = :> }
| GREATER EQUAL
{ result = :>= }
| NOT EQUAL
{ result = :!= }
| LESS GREATER
{ result = :!= }
| EQUAL
{ result = :== }
| EQUAL EQUAL
{ result = :== }
add: add PLUS mul
{ result = val }
| add MINUS mul
{ result = val }
| mul
mul: mul ASTERISK unary
{ result = val }
| mul SLASH unary
{ result = val }
| mul SLASH unary U
{ result = val }
| mul SLASH unary R
{ result = val }
| unary
unary: PLUS unary
{ result = val }
| MINUS unary
{ result = val }
| dice
dice: term D term
{ result = val }
| term D term filter_type term
{ result = val }
| term
filter_type: K H
{ result = :KH }
| K L
{ result = :KL }
| D H
{ result = :DH }
| D L
{ result = :DL }
term: PARENL add PARENR
{ result = val[1] }
| NUMBER
end
---- inner
def parse(source)
@tokens = tokenize(source)
do_parse()
end
def tokenize(source)
tokens = source.gsub(%r{[\+\-\*/DKHLUR()<>!=]}) { |e| " #{e} " }.split(" ")
tokens = tokens.map do |t|
type = token_type(t)
t = t.to_i if type == :NUMBER
[type, t]
end
tokens.push([false, '$'])
end
def token_type(t)
case t
when '+'
:PLUS
when '-'
:MINUS
when '*'
:ASTERISK
when '/'
:SLASH
when '('
:PARENL
when ')'
:PARENR
when '<'
:LESS
when '>'
:GREATER
when '='
:EQUAL
when '!'
:NOT
when /\A\d+\z/
:NUMBER
else
t.to_sym
end
end
def next_token
@tokens.shift
end
class RerollDice
token NUMBER R U C F PLUS MINUS ASTERISK SLASH PARENL PARENR BRACKETL BRACKETR LESS GREATER EQUAL NOT AT
rule
expr: notation bracket target at
{ result = val }
target: /* none */
| cmp_op term
{ result = val }
bracket: /* none */
| BRACKETL add BRACKETR
{ result = val }
| BRACKETL cmp_op add BRACKETR
{ result = val }
at: /* none */
| AT add
{ result = val }
| AT cmp_op add
{ result = val }
cmp_op: LESS EQUAL
{ result = :<= }
| LESS
{ result = :< }
| GREATER
{ result = :> }
| GREATER EQUAL
{ result = :>= }
| NOT EQUAL
{ result = :!= }
| LESS GREATER
{ result = :!= }
| EQUAL
{ result = :== }
| EQUAL EQUAL
{ result = :== }
notation: notation PLUS dice
{ result = val }
| dice
dice: term R term
{ result = val }
add: add PLUS mul
{ result = val }
| add MINUS mul
{ result = val }
| mul
mul: mul ASTERISK unary
{ result = val }
| mul SLASH unary round_type
{ result = val }
| unary
round_type: /* none */
| U
{ result = :ceil }
| C
{ result = :ceil }
| R
{ result = :round }
| F
{ result = :floor }
unary: PLUS unary
{ result = val }
| MINUS unary
{ result = val }
| term
term: PARENL add PARENR
{ result = val[1] }
| NUMBER
end
---- inner
def parse(source)
@tokens = tokenize(source)
do_parse()
end
def tokenize(source)
tokens = source.gsub(%r{[\+\-\*/()\[\]RUCF<>!=]}) { |e| " #{e} " }.split(" ")
tokens = tokens.map do |t|
type = token_type(t)
t = t.to_i if type == :NUMBER
[type, t]
end
tokens.push([false, '$'])
end
def token_type(t)
case t
when '+'
:PLUS
when '-'
:MINUS
when '*'
:ASTERISK
when '/'
:SLASH
when '('
:PARENL
when ')'
:PARENR
when '['
:BRACKETL
when ']'
:BRACKETR
when '<'
:LESS
when '>'
:GREATER
when '='
:EQUAL
when '!'
:NOT
when /\A\d+\z/
:NUMBER
else
t.to_sym
end
end
def next_token
@tokens.shift
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment