Skip to content

Instantly share code, notes, and snippets.

@jtgeibel
Created October 29, 2011 14:45
Show Gist options
  • Save jtgeibel/1324527 to your computer and use it in GitHub Desktop.
Save jtgeibel/1324527 to your computer and use it in GitHub Desktop.
Parsing Relay Logic with Ruby
require 'parslet'
class ML2Parser < Parslet::Parser
def consume_until terminator, consumable = any
(terminator.absent? >> consumable).repeat >> terminator
end
rule(:logic_section) { sp? >> (assign | comment).repeat}
rule(:statement) { sp >> expression.as(:exp) >> sp >> str('TO') >> sp >> coil_list.as(:to) >> sp? >> str(';') >> sp? }
rule(:assign) { (str('ASSIGN') >> statement).as(:v) | (str('NV.ASSIGN') >> statement).as(:nv) }
rule(:coil_list) { bit_name.as(:coil) >> (comma.maybe >> bit_name.as(:coil)).repeat }
rule(:comment) { (comment_ln | comment_ml) >> sp? }
rule(:comment_ln) { str('//') >> consume_until(newline) }
rule(:comment_ml) { str('%') >> consume_until(str "\\") }
rule(:expression) { or_exp.as(:or) | and_exp.as(:and) | atom } # The "or" operator has lowest precedence, so search for it first.
rule(:and_exp) { atom >> (and_op >> atom).repeat(1) }
rule(:or_exp) { (or_able) >> (or_op >> or_able).repeat(1)}
rule(:or_able) { and_exp.as(:and) | atom }
rule(:atom) { paren | contact}
rule(:paren) { lparen >> expression >> rparen }
rule(:lparen) { str('(') >> sp? }
rule(:rparen) { sp? >> str(')') }
rule(:comma) { str(',') >> sp? }
rule(:newline) { str("\r").maybe >> str("\n") }
rule(:and_op) { sp? >> str('*') >> sp? }
rule(:or_op) { sp? >> str('+') >> sp? }
rule(:not_op) { sp? >> str('~') >> sp? }
rule(:contact) { (not_op >> bit_name.as(:back)) | bit_name.as(:front) } # Can only not_op bits directly; Can't be used with parens like this: ~(expression)
rule(:bit_name) { (match['a-zA-Z_'] >> match['0-9a-zA-Z._'].repeat) | str('1') | str('0') }
rule(:sp) { match('\s').repeat(1) }
rule(:sp?) { sp.maybe }
root(:logic_section)
end
ASSIGN A + B * C * D * D + C * (D + E) * (D + Q + W) TO F;
ASSIGN A + B + C * D + E TO G;
ASSIGN A * B * C + (D * E) TO H;
ASSIGN A * B * C + D * E TO I;
.,. A ....................(F)
|. B .. C .. D .. D ..|
|. C ..,. D ...,. D ..|
| |. E .| |. Q .||
| |. W .||
.,. A .........(G)
|. B ......|
|. C .. D .|
|. ~E .....|
.,. A .. B .. C ....(H)
|. D .. E ......|
.,. A .. B .. C ....(I)
|. D .. E ......|
require 'mlk2/logic_ops'
class ML2Transform < Parslet::Transform
rule(:front => simple(:name)) { Contact.new(name, :front) }
rule(:back => simple(:name)) { Contact.new(name, :back) }
rule(:or => sequence(:opnd)) { Or.new(opnd) }
rule(:and => sequence(:opnd)) { And.new(opnd) }
rule(:coil => simple(:coil)) { coil.to_s }
rule(:exp => simple(:exp), :to => simple(:to)) { Statement.new(Array(to), exp) }
rule(:exp => simple(:exp), :to => sequence(:to)) { Statement.new(to, exp) }
rule(:v => simple(:statement)) { statement.type = :vital; statement }
rule(:nv => simple(:statement)) { statement.type = :nonvital; statement }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment