2

定義を継承するときに苦労していsetParseActionます(これを英語で表現する方法がわからないので、例を示します):

from __future__ import division
from decimal import Decimal

from pyparsing import Word, alphas, ParseException, Literal, CaselessLiteral \
        , Combine, Optional, nums, Or, Forward, ZeroOrMore, StringEnd, alphanums, Suppress \
        , sglQuotedString, dblQuotedString, Group \
        , restOfLine, Regex, stringEnd


class ASTNode(object):
    def __init__(self, tokens):
        self.tokens = tokens
        self.assignFields()

    def __str__(self):
        return self.__class__.__name__ + ':' + str(self.__dict__)
    __repr__ = __str__


class ConstantNode(ASTNode):
    def assignFields(self):
        #print "  ", self.tokens
        self.setValue(self.tokens[0])

    def transform(self, value):
        return value

    def setValue(self, value):
        self.constant = self.transform(value)
        del self.tokens


class StringNode(ConstantNode):
    pass


class BoolNode(ConstantNode):
    def transform(self, value):
        return bool(value)


class IntNode(ConstantNode):
    def transform(self, value):
        return int(value)


class FloatNode(ConstantNode):
    def transform(self, value):
        print value
        return Decimal(value)


class AssignmentNode(ASTNode):
    def assignFields(self):
        #print self.tokens
        self.lhs, self.rhs = self.tokens
        del self.tokens


LPAR, RPAR, LBRACK, RBRACK, LBRACE, RBRACE, SEMI, COMMA = map(Suppress, "()[]{};,")

PLUS = Literal("+")
MINUS = Literal("-")
MULT = Literal("*")
DIV = Literal("/")

ASSIGN = Literal("=")
POINT = Literal('.')

TRUE = Literal('True')
FALSE = Literal('False')

SEP = Literal(':').suppress()

NAME = Word(alphas + '_?', alphanums + '_?')
TYPE = SEP + NAME
COMMENT = "#" + restOfLine

BOOLEANS = TRUE | FALSE
BOOLEANS.setParseAction(BoolNode)

EXPR = Forward()

ADDOP = PLUS | MINUS
MULTOP = MULT | DIV
PLUSORMINUS = PLUS | MINUS

#Strings
STR = dblQuotedString.setParseAction(ConstantNode) | sglQuotedString.setParseAction(ConstantNode)

STRINGS = STR

#Numbers
NUMBER = Word(nums)
INTEGER = Combine(Optional(PLUSORMINUS) + NUMBER)
FLOATNUMBER = Combine(INTEGER.copy() +
                       Optional(POINT + Optional(NUMBER)) +
                       Optional(INTEGER.copy())
                )

MONEY = Combine(FLOATNUMBER.copy() + Word("$").suppress())
TYPED_FLOATNUMBER = Combine(FLOATNUMBER + Word(alphas))

INTEGER.setParseAction(IntNode)
FLOATNUMBER.setParseAction(FloatNode)

NUMBERS = MONEY | TYPED_FLOATNUMBER | FLOATNUMBER


TEST_GRAMMAR = """
#Single values
True
False
1 #Int32
1.0 #Float
1$ #MONEY
25.3mt #Typed number"""

すべてが解析されますが、Boolean ノードと Int ノードは呼び出されず、float のみが呼び出されます。

['True']
['False']
1
[FloatNode:{'constant': Decimal('1')}]
1.0
[FloatNode:{'constant': Decimal('1.0')}]
['1']
['25.3mt']
[ConstantNode:{'constant': "'hello world'"}]
[ConstantNode:{'constant': '"hello world"'}]
['2002-08-10']
['100000']
['2002-08-10-100000']
1
[AssignmentNode:{'rhs': FloatNode:{'constant': Decimal('1')}, 'lhs': 'x'}]
1.0
[AssignmentNode:{'rhs': FloatNode:{'constant': Decimal('1.0')}, 'lhs': 'x'}]
[AssignmentNode:{'rhs': '1', 'lhs': 'x'}]
[AssignmentNode:{'rhs': '12.2mt', 'lhs': 'x'}]

setParseAction が部分文法の定義に関連付けられていることを理解しています。FLOATNUMBERただし、に基づいているため、チェーンのようなものが「クリア」されないことがわかりましたINTEGER

4

1 に答える 1

0

実際の解析を行うコードを省略したので、次のコードを追加しました。

for line in TEST_GRAMMAR.splitlines():
    if not line or line[0] == '#': continue
    print (BOOLEANS^INTEGER^NUMBERS).parseString(line)

この出力を与える:

[BoolNode:{'constant': True}]
[BoolNode:{'constant': False}]
[IntNode:{'constant': 1}]
1.0
[FloatNode:{'constant': Decimal('1.0')}]
['1']
['25.3mt']

BoolNode の小さなバグも修正する必要がありました。

class BoolNode(ConstantNode):
    def transform(self, value):
        return value.lower()=='true' #bool(value)

ではtransform、値は文字列「True」または「False」のいずれかになりboolますが、これらの文字列の値はどちらも True です。空の文字列「」のみがブール値 False を返します。

問題の 1 つは、FLOAT の定義が INTEGER にも一致することです。そのため、FLOAT を再定義して、先頭、末尾、または組み込みの小数点を要求することを検討してください。「|」の代わりに「^」を使用してこれを回避しました 「または」演算子として。'^' は、指定されたすべての選択肢をテストし、最長一致の '|'を選択します。短絡して最初の一致を選択します。

于 2012-12-31T06:06:26.137 に答える