Created
December 3, 2020 14:57
-
-
Save ochaochaocha3/8f34c1ffd0c8ab6ca4d1442f54f82aa7 to your computer and use it in GitHub Desktop.
BCDiceのLALR(1)構文解析器をまとめようとした跡(reduce/reduce conflict多発のため却下)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BCDice::CommonCommand::Parser | |
token | |
ASTERISK | |
AT | |
BRACKETL | |
BRACKETR | |
C | |
CMP_OP | |
D | |
EQUAL | |
F | |
GREATER | |
H | |
K | |
L | |
LESS | |
MINUS | |
NOT | |
NUMBER | |
PARENL | |
PARENR | |
PLUS | |
QUESTION | |
R | |
S | |
SLASH | |
U | |
rule | |
command: add_dice | |
| reroll_dice | |
add_dice: secret add_dice_add | |
{ | |
secret, lhs = val | |
raise ParseError unless lhs.include_dice? | |
result = AddDice::Node::Command.new(secret, lhs) | |
} | |
| secret add_dice_add CMP_OP add_dice_target | |
{ | |
secret, lhs, cmp_op, rhs = val | |
raise ParseError if !lhs.include_dice? || rhs.include_dice? || cmp_op.nil? | |
result = AddDice::Node::Command.new(secret, lhs, cmp_op, rhs) | |
} | |
add_dice_target: add_dice_add | |
| QUESTION | |
{ result = AddDice::Node::UndecidedTarget.instance } | |
add_dice_add: add_dice_add PLUS add_dice_mul | |
{ | |
lhs = val[0] | |
op, rhs = expand_negate(:+, val[2]) | |
result = AddDice::Node::BinaryOp.new(lhs, op, rhs) | |
} | |
| add_dice_add MINUS add_dice_mul | |
{ | |
lhs = val[0] | |
op, rhs = expand_negate(:-, val[2]) | |
result = AddDice::Node::BinaryOp.new(lhs, op, rhs) | |
} | |
| add_dice_mul | |
add_dice_mul: add_dice_mul ASTERISK add_dice_unary | |
{ | |
lhs = val[0] | |
rhs = val[2] | |
result = AddDice::Node::BinaryOp.new(lhs, :*, rhs) | |
} | |
| add_dice_mul SLASH add_dice_unary add_dice_round_type | |
{ | |
lhs = val[0] | |
rhs = val[2] | |
divied_class = val[3] | |
result = divied_class.new(lhs, rhs) | |
} | |
| add_dice_unary | |
add_dice_round_type: /* none */ | |
{ result = AddDice::Node::DivideWithRoundingDown } | |
| U | |
{ result = AddDice::Node::DivideWithRoundingUp } | |
| R | |
{ result = AddDice::Node::DivideWithRoundingOff } | |
add_dice_unary: PLUS add_dice_unary | |
{ result = val[1] } | |
| MINUS add_dice_unary | |
{ | |
body = val[1] | |
result = body.is_a?(AddDice::Node::Negate) ? body.body : AddDice::Node::Negate.new(body) | |
} | |
| d_dice | |
d_dice: add_dice_term D add_dice_term | |
{ | |
times = val[0] | |
sides = val[2] | |
raise ParseError if times.include_dice? || sides.include_dice? | |
result = AddDice::Node::DiceRoll.new(times, sides) | |
} | |
| add_dice_term D | |
{ | |
times = val[0] | |
sides = AddDice::Node::Number.new(6) | |
raise ParseError if times.include_dice? | |
result = AddDice::Node::DiceRoll.new(times, sides) | |
} | |
| add_dice_term D add_dice_term add_dice_filter_type add_dice_term | |
{ | |
times = val[0] | |
sides = val[2] | |
filter = val[3] | |
n_filtering = val[4] | |
raise ParseError if times.include_dice? || sides.include_dice? || n_filtering.include_dice? | |
result = AddDice::Node::DiceRollWithFilter.new(times, sides, n_filtering, filter) | |
} | |
| add_dice_term | |
add_dice_filter_type: K H | |
{ result = AddDice::Node::DiceRollWithFilter::KEEP_HIGHEST } | |
| K L | |
{ result = AddDice::Node::DiceRollWithFilter::KEEP_LOWEST } | |
| D H | |
{ result = AddDice::Node::DiceRollWithFilter::DROP_HIGHEST } | |
| D L | |
{ result = AddDice::Node::DiceRollWithFilter::DROP_LOWEST } | |
add_dice_term: PARENL add_dice_add PARENR | |
{ result = AddDice::Node::Parenthesis.new(val[1]) } | |
| NUMBER | |
{ result = AddDice::Node::Number.new(val[0]) } | |
reroll_dice: secret reroll_dice_notations reroll_dice_target | |
{ | |
result = RerollDice::Node::Command.new( | |
secret: val[0], | |
notations: val[1], | |
cmp_op: val[2][:cmp_op], | |
target_number: val[2][:target], | |
source: @lexer.source | |
) | |
} | |
| secret reroll_dice_notations bracket reroll_dice_target | |
{ | |
target = val[3] | |
threshold = val[2] | |
result = RerollDice::Node::Command.new( | |
secret: val[0], | |
notations: val[1], | |
cmp_op: target[:cmp_op], | |
target_number: target[:target], | |
reroll_cmp_op: threshold[:cmp_op], | |
reroll_threshold: threshold[:threshold], | |
source: @lexer.source | |
) | |
} | |
| secret reroll_dice_notations reroll_dice_target at | |
{ | |
target = val[2] | |
threshold = val[3] | |
result = RerollDice::Node::Command.new( | |
secret: val[0], | |
notations: val[1], | |
cmp_op: target[:cmp_op], | |
target_number: target[:target], | |
reroll_cmp_op: threshold[:cmp_op], | |
reroll_threshold: threshold[:threshold], | |
source: @lexer.source | |
) | |
} | |
reroll_dice_target: /* none */ | |
{ result = {} } | |
| CMP_OP arithmetic_term | |
{ | |
cmp_op, target = val | |
raise ParseError unless cmp_op | |
result = {cmp_op: cmp_op, target: target} | |
} | |
bracket: BRACKETL arithmetic_add BRACKETR | |
{ result = {threshold: val[1]} } | |
| BRACKETL CMP_OP arithmetic_add BRACKETR | |
{ | |
cmp_op = val[1] | |
threshold = val[2] | |
raise ParseError unless cmp_op | |
result = {cmp_op: cmp_op, threshold: threshold} | |
} | |
at: AT arithmetic_add | |
{ result = {threshold: val[1]} } | |
| AT CMP_OP arithmetic_add | |
{ | |
cmp_op = val[1] | |
threshold = val[2] | |
raise ParseError unless cmp_op | |
result = {cmp_op: cmp_op, threshold: threshold} | |
} | |
reroll_dice_notations: reroll_dice_notations PLUS r_dice | |
{ | |
notations = val[0] | |
notations.push(val[2]) | |
result = notations | |
} | |
| r_dice | |
{ result = [val[0]] } | |
r_dice: arithmetic_term R arithmetic_term | |
{ | |
times = val[0] | |
sides = val[2] | |
result = RerollDice::Node::Notation.new(times, sides) | |
} | |
secret: /* none */ | |
{ result = false } | |
| S | |
{ result = true } | |
arithmetic_add: arithmetic_add PLUS arithmetic_mul | |
{ result = Arithmetic::Node::BinaryOp(val[0], :+, val[2]) } | |
| arithmetic_add MINUS arithmetic_mul | |
{ result = Arithmetic::Node::BinaryOp(val[0], :-, val[2]) } | |
| arithmetic_mul | |
arithmetic_mul: arithmetic_mul ASTERISK arithmetic_unary | |
{ result = Arithmetic::Node::BinaryOp(val[0], :*, val[2]) } | |
| arithmetic_mul SLASH arithmetic_unary arithmetic_round_type | |
{ | |
divied_class = val[3] | |
result = divied_class.new(val[0], val[2]) | |
} | |
| arithmetic_unary | |
arithmetic_round_type: /* none */ | |
{ result = Arithmetic::Node::DivideWithGameSystemDefault } | |
| U | |
{ result = Arithmetic::Node::DivideWithCeil } | |
| C | |
{ result = Arithmetic::Node::DivideWithCeil } | |
| R | |
{ result = Arithmetic::Node::DivideWithRound } | |
| F | |
{ result = Arithmetic::Node::DivideWithFloor } | |
arithmetic_unary: PLUS arithmetic_unary | |
{ result = val[1] } | |
| MINUS arithmetic_unary | |
{ result = Arithmetic::Node::Negative.new(val[1]) } | |
| arithmetic_term | |
arithmetic_term: PARENL arithmetic_add PARENR | |
{ result = val[1] } | |
| NUMBER | |
{ result = Arithmetic::Node::Number.new(val[0]) } | |
end | |
---- header | |
require "bcdice/common_command/lexer" | |
require "bcdice/common_command/add_dice/node" | |
require "bcdice/common_command/reroll_dice/node" | |
require "bcdice/arithmetic/node" | |
---- inner | |
def self.parse(source) | |
new.parse(source) | |
end | |
def parse(source) | |
@lexer = Lexer.new(source) | |
do_parse() | |
rescue ParseError | |
nil | |
end | |
private | |
def next_token | |
@lexer.next_token | |
end | |
# 加減算の右辺が負数である場合に加減算を逆転させる | |
def expand_negate(op, rhs) | |
if rhs.is_a?(AddDice::Node::Negate) | |
if op == :+ | |
return [:-, rhs.body] | |
elsif op == :- | |
return [:+, rhs.body] | |
end | |
end | |
[op, rhs] | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment