Commit 2c9dbbc3 authored by Igor Dejanovic's avatar Igor Dejanovic

Updated PEG parser construction to take into account new improvements.

parent 55931c6d
...@@ -8,13 +8,11 @@ ...@@ -8,13 +8,11 @@
####################################################################### #######################################################################
from __future__ import print_function from __future__ import print_function
from kivy.lang import ParserException
__all__ = ['ParserPEG']
from arpeggio import * from arpeggio import *
from arpeggio import RegExMatch as _ from arpeggio import RegExMatch as _
__all__ = ['ParserPEG']
# PEG Lexical rules # PEG Lexical rules
def LEFT_ARROW(): return "<-" def LEFT_ARROW(): return "<-"
...@@ -27,21 +25,22 @@ def NOT(): return "!" ...@@ -27,21 +25,22 @@ def NOT(): return "!"
def OPEN(): return "(" def OPEN(): return "("
def CLOSE(): return ")" def CLOSE(): return ")"
def regex(): return "r'", _(r"(\\\'|[^\'])*"),"'" def regex(): return "r'", _(r"(\\\'|[^\'])*"),"'"
def rule_identifier(): return _(r"[a-zA-Z_]([a-zA-Z_]|[0-9])*") def rule_name(): return _(r"[a-zA-Z_]([a-zA-Z_]|[0-9])*")
def rule_crossref(): return rule_name
#def literal(): return [_(r"\'(\\\'|[^\'])*\'"),_(r'"[^"]*"')] #def literal(): return [_(r"\'(\\\'|[^\'])*\'"),_(r'"[^"]*"')]
def literal(): return _(r'(\'(\\\'|[^\'])*\')|("[^"]*")') def str_match(): return _(r'(\'(\\\'|[^\'])*\')|("[^"]*")')
def comment(): return "//", _(".*\n") def comment(): return "//", _(".*\n")
# PEG syntax rules # PEG syntax rules
def grammar(): return OneOrMore(rule), EOF def grammar(): return OneOrMore(rule), EOF
def rule(): return rule_identifier, LEFT_ARROW, ordered_choice, ";" def rule(): return rule_name, LEFT_ARROW, ordered_choice, ";"
def ordered_choice(): return sequence, ZeroOrMore(SLASH, sequence) def ordered_choice(): return sequence, ZeroOrMore(SLASH, sequence)
def sequence(): return OneOrMore(prefix) def sequence(): return OneOrMore(prefix)
def prefix(): return Optional([AND,NOT]), sufix def prefix(): return Optional([AND,NOT]), sufix
def sufix(): return expression, Optional([QUESTION, STAR, PLUS]) def sufix(): return expression, Optional([QUESTION, STAR, PLUS])
def expression(): return [regex,(rule_identifier, Not(LEFT_ARROW)), def expression(): return [regex, rule_crossref,
(OPEN, ordered_choice, CLOSE), (OPEN, ordered_choice, CLOSE),
literal] str_match]
# ------------------------------------------------------------------ # ------------------------------------------------------------------
...@@ -58,30 +57,34 @@ class PEGSemanticAction(SemanticAction): ...@@ -58,30 +57,34 @@ class PEGSemanticAction(SemanticAction):
.format(rule_name)) .format(rule_name))
def second_pass(self, parser, node): def second_pass(self, parser, node):
'''
Resolving cross-references in second pass.
'''
if isinstance(node, CrossRef): if isinstance(node, CrossRef):
return self._resolve(parser, node.rule_name) return self._resolve(parser, node.rule_name)
elif isinstance(node, ParsingExpression): elif isinstance(node, ParsingExpression):
for i, n in enumerate(node.nodes): for i, n in enumerate(node.nodes):
if isinstance(n, CrossRef): if isinstance(n, CrossRef):
node[i] = self._resolve(parser, n.rule_name) node.nodes[i] = self._resolve(parser, n.rule_name)
return node return node
else: else:
raise SemanticError("Invalid type '{}' after first pass." raise SemanticError("Invalid type '{}'({}) after first pass."
.format(type(node))) .format(type(node), str(node)))
class SemGrammar(SemanticAction): class SemGrammar(SemanticAction):
def first_pass(self, parser, node, children): def first_pass(self, parser, node, children):
print(parser.peg_rules)
return parser.peg_rules[parser.root_rule_name] return parser.peg_rules[parser.root_rule_name]
class SemRule(PEGSemanticAction): class SemRule(PEGSemanticAction):
def first_pass(self, parser, node, children): def first_pass(self, parser, node, children):
rule_name = children[0] rule_name = children[0]
if len(children) > 4: if len(children) > 2:
retval = Sequence(nodes=children[2:-1]) retval = Sequence(nodes=children[1:])
else: else:
retval = children[2] retval = children[1]
retval.rule = rule_name retval.rule = rule_name
retval.root = True retval.root = True
...@@ -89,7 +92,10 @@ class SemRule(PEGSemanticAction): ...@@ -89,7 +92,10 @@ class SemRule(PEGSemanticAction):
parser.peg_rules = {} # Used for linking phase parser.peg_rules = {} # Used for linking phase
parser.peg_rules["EndOfFile"] = EndOfFile() parser.peg_rules["EndOfFile"] = EndOfFile()
# Keep a map of parser rules for cross reference
# resolving.
parser.peg_rules[rule_name] = retval parser.peg_rules[rule_name] = retval
return retval return retval
...@@ -98,14 +104,16 @@ class SemSequence(PEGSemanticAction): ...@@ -98,14 +104,16 @@ class SemSequence(PEGSemanticAction):
if len(children) > 1: if len(children) > 1:
return Sequence(nodes=children) return Sequence(nodes=children)
else: else:
# If only one child rule exists reduce.
return children[0] return children[0]
class SemOrderedChoice(PEGSemanticAction): class SemOrderedChoice(PEGSemanticAction):
def first_pass(self, parser, node, children): def first_pass(self, parser, node, children):
if len(children) > 1: if len(children) > 1:
retval = OrderedChoice(nodes=children[::2]) retval = OrderedChoice(nodes=children)
else: else:
# If only one child rule exists reduce.
retval = children[0] retval = children[0]
return retval return retval
...@@ -122,6 +130,7 @@ class SemPrefix(PEGSemanticAction): ...@@ -122,6 +130,7 @@ class SemPrefix(PEGSemanticAction):
else: else:
retval.nodes = [children[1]] retval.nodes = [children[1]]
else: else:
# If there is no optional prefix reduce.
retval = children[0] retval = children[0]
return retval return retval
...@@ -148,23 +157,20 @@ class SemSufix(PEGSemanticAction): ...@@ -148,23 +157,20 @@ class SemSufix(PEGSemanticAction):
class SemExpression(PEGSemanticAction): class SemExpression(PEGSemanticAction):
def first_pass(self, parser, node, children): def first_pass(self, parser, node, children):
if len(children) == 1:
return children[0] return children[0]
else:
return children[1]
class SemIdentifier(PEGSemanticAction): class SemRuleCrossRef(SemanticAction):
def first_pass(self, parser, node, children): def first_pass(self, parser, node, children):
return super(SemIdentifier, self).first_pass(parser, node, children) return CrossRef(node.value)
class SemRegEx(SemanticAction): class SemRegEx(SemanticAction):
def first_pass(self, parser, node, children): def first_pass(self, parser, node, children):
return RegExMatch(children[1]) return RegExMatch(children[0])
class SemLiteral(SemanticAction): class SemStrMatch(SemanticAction):
def first_pass(self, parser, node, children): def first_pass(self, parser, node, children):
match_str = node.value[1:-1] match_str = node.value[1:-1]
match_str = match_str.replace("\\'", "'") match_str = match_str.replace("\\'", "'")
...@@ -179,9 +185,9 @@ sequence.sem = SemSequence() ...@@ -179,9 +185,9 @@ sequence.sem = SemSequence()
prefix.sem = SemPrefix() prefix.sem = SemPrefix()
sufix.sem = SemSufix() sufix.sem = SemSufix()
expression.sem = SemExpression() expression.sem = SemExpression()
rule_crossref.sem = SemRuleCrossRef()
regex.sem = SemRegEx() regex.sem = SemRegEx()
rule_identifier.sem = SemIdentifier() str_match.sem = SemStrMatch()
literal.sem = SemLiteral()
class ParserPEG(Parser): class ParserPEG(Parser):
...@@ -205,4 +211,5 @@ class ParserPEG(Parser): ...@@ -205,4 +211,5 @@ class ParserPEG(Parser):
parser = ParserPython(grammar, comment, reduce_tree=False, debug=True) parser = ParserPython(grammar, comment, reduce_tree=False, debug=True)
parser.root_rule_name = self.root_rule_name parser.root_rule_name = self.root_rule_name
parser.parse(language_def) parser.parse(language_def)
return parser.getASG() return parser.getASG()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment