1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
# This module tries to implement ISO 14977 standard with pyparsing.
# pyparsing version 1.1 or greater is required.
# ISO 14977 standardize The Extended Backus-Naur Form(EBNF) syntax.
# You can read a final draft version here:
# http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html
#
# Submitted 2004 by Seo Sanghyeon
#
from pyparsing import *
all_names = '''
integer
meta_identifier
terminal_string
optional_sequence
repeated_sequence
grouped_sequence
syntactic_primary
syntactic_factor
syntactic_term
single_definition
definitions_list
syntax_rule
syntax
'''.split()
integer = Word(nums)
meta_identifier = Word(alphas, alphanums + '_')
terminal_string = Suppress("'") + CharsNotIn("'") + Suppress("'") ^ \
Suppress('"') + CharsNotIn('"') + Suppress('"')
definitions_list = Forward()
optional_sequence = Suppress('[') + definitions_list + Suppress(']')
repeated_sequence = Suppress('{') + definitions_list + Suppress('}')
grouped_sequence = Suppress('(') + definitions_list + Suppress(')')
syntactic_primary = optional_sequence ^ repeated_sequence ^ \
grouped_sequence ^ meta_identifier ^ terminal_string
syntactic_factor = Optional(integer + Suppress('*')) + syntactic_primary
syntactic_term = syntactic_factor + Optional(Suppress('-') + syntactic_factor)
single_definition = delimitedList(syntactic_term, ',')
definitions_list << delimitedList(single_definition, '|')
syntax_rule = meta_identifier + Suppress('=') + definitions_list + \
Suppress(';')
ebnfComment = ( "(*" +
ZeroOrMore( CharsNotIn("*") | ( "*" + ~Literal(")") ) ) +
"*)" ).streamline().setName("ebnfComment")
syntax = OneOrMore(syntax_rule)
syntax.ignore(ebnfComment)
def do_integer(str, loc, toks):
return int(toks[0])
def do_meta_identifier(str, loc, toks):
if toks[0] in symbol_table:
return symbol_table[toks[0]]
else:
forward_count.value += 1
symbol_table[toks[0]] = Forward()
return symbol_table[toks[0]]
def do_terminal_string(str, loc, toks):
return Literal(toks[0])
def do_optional_sequence(str, loc, toks):
return Optional(toks[0])
def do_repeated_sequence(str, loc, toks):
return ZeroOrMore(toks[0])
def do_grouped_sequence(str, loc, toks):
return Group(toks[0])
def do_syntactic_primary(str, loc, toks):
return toks[0]
def do_syntactic_factor(str, loc, toks):
if len(toks) == 2:
# integer * syntactic_primary
return And([toks[1]] * toks[0])
else:
# syntactic_primary
return [ toks[0] ]
def do_syntactic_term(str, loc, toks):
if len(toks) == 2:
# syntactic_factor - syntactic_factor
return NotAny(toks[1]) + toks[0]
else:
# syntactic_factor
return [ toks[0] ]
def do_single_definition(str, loc, toks):
toks = toks.asList()
if len(toks) > 1:
# syntactic_term , syntactic_term , ...
return And(toks)
else:
# syntactic_term
return [ toks[0] ]
def do_definitions_list(str, loc, toks):
toks = toks.asList()
if len(toks) > 1:
# single_definition | single_definition | ...
return Or(toks)
else:
# single_definition
return [ toks[0] ]
def do_syntax_rule(str, loc, toks):
# meta_identifier = definitions_list ;
assert toks[0].expr is None, "Duplicate definition"
forward_count.value -= 1
toks[0] << toks[1]
return [ toks[0] ]
def do_syntax(str, loc, toks):
# syntax_rule syntax_rule ...
return symbol_table
symbol_table = {}
class forward_count:
pass
forward_count.value = 0
for name in all_names:
expr = vars()[name]
action = vars()['do_' + name]
expr.setName(name)
expr.setParseAction(action)
#~ expr.setDebug()
def parse(ebnf, given_table={}):
symbol_table.clear()
symbol_table.update(given_table)
forward_count.value = 0
table = syntax.parseString(ebnf)[0]
assert forward_count.value == 0, "Missing definition"
for name in table:
expr = table[name]
expr.setName(name)
#~ expr.setDebug()
return table
|