python 由robturtle创建的DFA - https://repl.it/EzaW/28
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 由robturtle创建的DFA - https://repl.it/EzaW/28相关的知识,希望对你有一定的参考价值。
corrects = [('0', 0), ('0.', 0), ('.0', 0), ('1.', 1), ('.1', .1),
('123.', 123), ('123', 123), ('.123', .123), ('0.0', 0), ('1.0', 1),
('0.1', .1), ('1.1', 1.1), ('12.1', 12.1), ('1.12', 1.12),
('0e0', 0), ('0e123', 0), ('1e0', 1), ('1e123', 1), ('123e0', 1),
('123e13', 123e13), ('3.14e7', 3.14e7), ('3.14e0', 1),
('3.14e+7', 3.14e7), ('3.14e-7', 3.14e-7), ('+3.14e+7', 3.14e7),
('-3.14e-7', -3.14e-7), ('-3.14E+7', -3.14e7),
('-3.141592653e-3', -3.141592653e-3)]
wrongs = ['+', '-', '++', '--', '+-', '.', '..', 'e', 'E',
'eE', 'EE', 'yang', 'f', '3e', 'e7', '3e-', '4e+',
'+3e', '-4E', '1.e', '.1e', '1.2E', '1.2e3.4', '1.2e.4',
'1.2e4.', '+1.2e1+', '1.2e1+', '1.2E1+2', '1.2f1', '-1.2f+12',
'1.fe+1.']
def test(parser):
for s, v in corrects:
try:
value = parser(s)
if abs(value - v) > 1e-5:
print('Wrong result for {!r}, expect {:5g}, got {:5g} instead'.format(s, v, value))
else:
print('{!r}: pass'.format(s))
except SyntaxError as err:
print('Wrong result for {!r}, expect {:5g}, got SyntaxError:\n{}'.format(s, v, err))
for s in wrongs:
try:
value = parser(s)
print('Wrong result for {!r}, expect SyntaxError, got {:5g} instead'.format(s, value))
except SyntaxError:
print('{!r}: pass'.format(s))
import string
from DFA import parser
@parser
class Power(object):
'''Get the exponent part value
syntax: <"e"|"E"> ["+"|"-"] <digits+>
'''
def __init__(self):
self.sign = 1
self.power = 0
def addDigit(self, c):
self.power = self.power * 10 + ord(c) - ord('0')
def setSign(self, c):
self.sign = 1 if c == '+' else -1
def get(self):
return self.sign * self.power
rules = [
{ 'eE': (1, None) },
{
'+-': (3, setSign),
string.digits: (2, addDigit)
},
{ string.digits: (2, addDigit) },
{ string.digits: (2, addDigit) }
]
terminals = (2,)
examples = ['e', '3', 'E', 'e+', 'E-',
'e-', 'E+', 'e+31109', 'e0',
'E1', 'e-13412', 'e++', 'e--',
'E+-', 'E-+', 'e1e4', 'e4+3',
'e13.2']
def runExample():
print('-'*40)
print('{:^40s}'.format('Exponent Parser Demo:'))
print('-'*40)
for e in examples:
try:
power = Power.parse(e)
print('Correct: {}'.format(power))
except SyntaxError as err:
print(err)
print('-'*40)
#runExample()
import NFA
from collections import defaultdict
from functools import reduce
from copy import deepcopy
class State:
id = 0
def __init__(self):
self.edges = defaultdict(lambda: set())
self.id = State.id
State.id += 1
def __repr__(self):
return str(self.id)
def link(self, char, dest):
self.edges[char].add(dest)
def __getitem__(self, char):
return self.edges[char]
def epsilonClosure(self):
met = set()
current = {self}
while len(current) > 0:
met = met | current
current = reduce(set.union, map(lambda s: set(s[None]), current), set()) - met
return met
def copy(self, mapping = {}):
clone = State()
mapping[self] = clone
for char, destinations in self.edges.items():
for dest in destinations:
if dest not in mapping:
mapping[dest] = dest.copy(mapping)
clone.link(char, mapping[dest])
return clone
def children(self):
return reduce(set.union, self.edges.values(), set())
def depthFirst(self, visitor, met = None):
if met is None:
met = set()
met.add(self)
visitor(self)
print('children = {}'.format(self.children()))
print('met = {}'.format(met))
unmet = self.children() - met
print('unmet = {}'.format(unmet))
for child in self.children() - met:
if child not in met:
child.depthFirst(visitor, met)
def printEdges(self):
self.depthFirst(lambda v: print('{!r} -> {}'.format(v, v.children())))
l = [None] * 5
for i in range(len(l)):
l[i] = State()
l[0].link(1, l[1])
l[0].link(1, l[2])
l[1].link(3, l[0])
l[1].link(5, l[2])
l[2].link(7, l[3])
l[2].link(6, l[4])
l[4].link(2, l[0])
l[4].link(1, l[3])
l[0].depthFirst(lambda v: print(v))
l[0].printEdges()
print('-'*40)
l[0].copy().depthFirst(lambda v: print(v))
import string
import NFA
from NFA import NFA
'''
floatLiteral = [sign] pointfloat [exp]
pointfloat = [intpart] fraction | intpart ["."]
intpart = [0-9]+
fraction = "." intpart
exp = /[eE]/ [sign] intpart
'''
sign = NFA().concat('-+').oneOrZero()
intpart = NFA().concat(string.digits).oneOrMore()
fraction = NFA().concat('.').concat(intpart)
pointfloat = intpart.oneOrZero().concat(None, fraction)
pointfloat.either(intpart.concat(NFA().concat('.').oneOrZero()))
exp = NFA().concat('eE').concat(None, sign).concat(None, intpart).oneOrZero()
floatLiteral = sign.concat(pointfloat).concat(exp)
def floatParser(chars):
if floatLiteral.match(chars):
return 0
else:
raise SyntaxError('error')
from DFA import parser
'''
Your task is to write a parser that convert a string into a floating point number.
'''
@parser
class Float:
rules = {
0: {}
}
terminals = ()
def get(self):
return 0
def makeStateAutomata(rules, terminals, resultGetter):
'''
Rules should be indexed and has element at index 0 as initial state.
For each rule, there should be zero or more tranfer entries, where an
entry is a key-value pair, the key will be tested against the input
char by keyword `in`. And the value is a 2-tuple, where the first one
is the next state, and the second one is the payload function that will
be executed when transfer took place.
Terminals should be a iterable containing all the terminating states.
ResultGetter should be a function used for returning value.
Example:
class IntPattern:
rules = {
0 : {
'123456789': (1, addDigit),
},
1: {
'0123456789': (1, addDigit),
}
}
terminals = (1,)
def __init__(self):
self.value = 0
def addDigit(self, char):
self.value = self.value * 10 + ord(char) - ord('0')
def get(self):
return self.value
intParser = makeStateAutomata(IntPattern.rules, IntPattern.terminals, IntPattern.get)
value = intParser(IntPattern(), '309')
^- use an instance to store the parsing result
'''
def startAutomata(obj, chars):
state = 0
i = 0
for i, c in enumerate(chars):
for rule in rules[state]:
if c in rule:
pair = rules[state][rule]
state = pair[0]
if pair[1] is not None:
pair[1](obj, c)
break
else:
state = 0
break
else:
i += 1
if state not in terminals:
raise SyntaxError(chars + '\n' + ' '*i + '^')
return resultGetter(obj)
return startAutomata
def parser(clz):
'''A convenient decorator to add a parse functionality to a type
Example:
@parser
class IntPattern: # as described above
value = IntPattern.parse('309')
'''
if not (hasattr(clz, 'rules') and hasattr(clz, 'terminals') and hasattr(clz, 'get')):
raise TypeError(
"type {!r} should has attributes 'rules', 'terminals' and 'get'".format(clz))
clz.parser = makeStateAutomata(clz.rules, clz.terminals, clz.get)
clz.parse = lambda chars: clz.parser(clz(), chars)
return clz
以上是关于python 由robturtle创建的DFA - https://repl.it/EzaW/28的主要内容,如果未能解决你的问题,请参考以下文章