Open gogotanaka opened 10 years ago
I suggest you begin with the parser. Hilbert language looks regular enough that you might want to look at the parslet gem: https://github.com/kschiess/parslet
To follow up, please look at the following example code which I cooked up in about an hour:
# coding: utf-8
require 'parslet'
require 'awesome_print'
class Hilbert < Parslet::Parser
rule(:space) { match('\s').repeat(1) }
rule(:space?) { space.maybe }
rule(:comma) { str(',') }
rule(:lparen) { str('(') }
rule(:rparen) { str(')') }
rule(:lbracket) { str('[') }
rule(:rbracket) { str(']') }
# things
rule(:integer) { match('[0-9]').repeat(1) >> space? }
rule(:proposition) { negation.maybe >> match('[A-Z]').as(:identifier) >> space? }
rule(:variable) { match['a-z'] >> space? }
rule(:infinity) { str('oo') }
rule(:pi) { str('pi') }
rule(:e) { str('e') }
# embedded functions
rule(:sin) { str('sin') }
rule(:cos) { str('cos') }
rule(:tan) { str('tan') }
rule(:log) { str('log') }
rule(:embedded_function) { (sin | cos | tan | log) }
# operators
rule(:conjunction) { str('&') >> space? }
rule(:disjunction) { str('|') >> space? }
rule(:material_implication) { str('->') >> space? }
rule(:negation) { str('~') }
rule(:logical_connective) { conjunction | disjunction | material_implication }
rule(:sigma) { str('∑') }
# expressions
rule(:compound_proposition) {
negation.as(:operator) >> proposition.as(:operand) |
proposition.as(:lhs) >> logical_connective.as(:operator) >> logical_expression.as(:rhs)
}
rule(:logical_expression) {
lparen.maybe >> compound_proposition.as(:proposition) >> rparen.maybe |
lparen.maybe >> proposition.as(:proposition) >> rparen.maybe
}
rule(:summation) { sigma >> lbracket >> variable >> str('=') >> integer.as(:start) >> comma >> integer.as(:end) >> rbracket >> space? >> variable }
rule(:numeric_expression) { integer | lparen >> integer >> rparen | summation.as(:summation) }
rule(:expression) { logical_expression | numeric_expression }
root(:expression)
end
def parse(txt)
Hilbert.new.parse(txt)
rescue Parslet::ParseFailed => e
puts e.cause.ascii_tree
end
ap parse('123')
ap parse('(123)')
ap parse('A')
ap parse('B | C')
ap parse('B & C | D -> E')
ap parse('(A -> (B))')
ap parse('~A')
ap parse('∑[x=0,10] x')
This is far from complete and far from ideal but it should certainly show how you can quickly use PEG parsers made with parslet to generate ASTs from simple expressions. This looks like a major improvement over the regex-based solutions you currently have. Please let me know how else I can help.
@yonkeltron I'm so sorry for the delay in response. Actually I didn't wanna use parse which depend on other library, because using parser which written by Ruby itself is not so popular. So I was afraid of using it.
But now, I found parslet which you suggest to me is reliable enough to use and I think even if parslet has problem, it's not difficult to send patch.
So I'm gonna use it and code you wrote. I'm really appreciate it.
@yonkeltron
To follow up, please look at the following example code which I cooked up in about an hour:
oh... you'er so awesome! even use parslet I think your job is so quick and good quality!
And now it's obvious fact I've wasted time so far...!
First of all....