Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  parse_pgen.py   Sprache: Python

 
#!/usr/bin/env python

"""parse_pgen.py - Parse grammars written in the pgen parser specification language.

I'm not sure I want to keep this pgen mini-language around; ignore this for now.
"""

import sys
from collections import namedtuple

from .lexer import LexicalGrammar
from .grammar import Grammar, Production, CallMethod, is_concrete_element, Optional
from . import gen
from . import parse_pgen_generated


pgen_lexer = LexicalGrammar(
    "goal nt var token { } ; ? = => ( ) ,",
    r'([ \t\r\n]|#.*)*',
    IDENT=r'[A-Za-z_](?:\w|[_-])*',
    STR=r'"[^\\\n"]*"',
    MATCH=r'\$(?:0|[1-9][0-9]*)',
    COMMENT=r'//.*',
)


def list_of(e, allow_comments=False):
    nt = e + 's'
    prods = [
        Production([e], CallMethod('single', (0,))),
        Production([nt, e], CallMethod('append', (0, 1))),
    ]
    if allow_comments:
        prods.append(Production(['COMMENT'], CallMethod('empty', (0,))))
    return prods


def call_method(name, body):
    arg_indexes = []
    current = 0
    for e in body:
        if is_concrete_element(e):
            if e not in discards:
                arg_indexes.append(current)
            current += 1

    return CallMethod(name, tuple(arg_indexes))


def prod(body, reducer):
    if isinstance(reducer, str):
        reducer = call_method(reducer, body)
    return Production(body, reducer)


discards = set('token var nt goal Some None = => ; ( ) { } , ?'.split())

pgen_grammar = Grammar(
    {
        'grammar': [
            [Optional('token_defs'), 'nt_defs']
        ],
        'token_defs': list_of('token_def'),
        'token_def': [
            prod(['token''IDENT''=''STR'';'], 'const_token'),
            prod(['var''token''IDENT'';'], 'var_token'),
        ],
        'nt_defs': [
            prod(['nt_def'], 'nt_defs_single'),
            prod(['nt_defs''nt_def'], 'nt_defs_append'),
        ],
        'nt_def': [
            prod([Optional('COMMENT'), Optional('goal'), 'nt''IDENT''{',
                  Optional('prods'), '}'], 'nt_def'),
        ],
        'prods': list_of('prod', allow_comments=True),
        'prod': [
            prod(['terms', Optional('reducer'), ';'], 'prod'),
        ],
        'terms': list_of('term'),
        'term': [
            ['symbol'],
            prod(['symbol''?'], 'optional'),
        ],
        'symbol': [
            prod(['IDENT'], 'ident'),
            prod(['STR'], 'str'),
        ],
        'reducer': [
            prod(['=>''expr'], 1)
        ],
        'expr': [
            prod(['MATCH'], 'expr_match'),
            prod(['IDENT''(', Optional('expr_args'), ')'], 'expr_call'),
            prod(['Some''(''expr'')'], 'expr_some'),
            prod(['None'], 'expr_none'),
        ],
        'expr_args': [
            prod(['expr'], 'args_single'),
            prod(['expr_args'',''expr'], 'args_append'),
        ],
    },
    goal_nts=['grammar'],
    variable_terminals=['IDENT''STR''MATCH''COMMENT']
)


Literal = namedtuple("Literal""chars")

default_token_list = [
    ("Var""var"),
    ("Token""token"),
    ("Goal""goal"),
    ("Nt""nt"),
    ("IDENT"None),
    ("STR"None),
    ("OpenBrace""{"),
    ("CloseBrace""}"),
    ("OpenParenthesis""("),
    ("CloseParenthesis"")"),
    ("Colon"":"),
    ("EqualSign""="),
    ("Asterisk""*"),
    ("PlusSign""+"),
    ("MinusSign""-"),
    ("Slash""/"),
    ("Semicolon"";"),
    ("QuestionMark""?"),
    ("RightArrow""->"),
    ("Comma"","),
]


class AstBuilder:
    def grammar(self, token_defs, nt_defs):
        nonterminals, goal_nts = nt_defs
        return (token_defs or default_token_list, nonterminals, goal_nts)

    def empty(self, value):
        return []

    def single(self, value):
        return [value]

    def append(self, values, value):
        values.append(value)
        return values

    def const_token(self, name, picture):
        assert picture[0] == '"'
        assert picture[-1] == '"'
        return (name, picture[1:-1])

    def var_token(self, name):
        return (name, None)

    def comment(self, comment):
        pass

    def nt_defs_single(self, nt_def):
        return self.nt_defs_append(({}, []), nt_def)

    def nt_defs_append(self, grammar_in, nt_def):
        is_goal, nt, prods = nt_def
        grammar, goal_nts = grammar_in
        if nt in grammar:
            raise ValueError("multiple definitions for nt {}".format(nt))
        grammar[nt] = prods
        if is_goal:
            goal_nts.append(nt)
        return grammar, goal_nts

    def nt_def(self, _comment, goal_kw, ident, prods):
        is_goal = goal_kw == "goal"
        prods = [Production(body, reducer) for body, reducer in prods]
        return (is_goal, ident, prods)

    def prod(self, symbols, reducer):
        if reducer is None:
            if sum(1 for e in symbols if is_concrete_element(e)) == 1:
                reducer = 0
            else:
                raise ValueError("reducer required for {!r}".format(symbols))
        return (symbols, reducer)

    def optional(self, sym):
        return Optional(sym)

    def ident(self, sym):
        return sym

    def str(self, sym):
        assert len(sym) > 1
        assert sym[0] == '"'
        assert sym[-1] == '"'
        chars = sym[1:-1]  # This is a bit sloppy.
        return Literal(chars)

    def expr_match(self, match):
        assert match.startswith('$')
        return int(match[1:])

    def expr_call(self, ident, args):
        return CallMethod(ident, tuple(args or ()))

    def args_single(self, expr):
        return [expr]

    def args_append(self, args, arg):
        args.append(arg)
        return args


def check_grammar(result):
    tokens, nonterminals, goal_nts = result
    tokens_by_name = {}
    tokens_by_image = {}
    for name, image in tokens:
        if name in tokens_by_name:
            raise ValueError("token `{}` redeclared".format(name))
        tokens_by_name[name] = image
        if image is not None and image in tokens_by_image:
            raise ValueError("multiple tokens look like \"{}\"".format(image))
        tokens_by_image[image] = name
        if name in nonterminals:
            raise ValueError("`{}` is declared as both a token and a nonterminal (pick one)".format(name))

    def check_element(nt, i, e):
        if isinstance(e, Optional):
            return Optional(check_element(nt, i, e.inner))
        elif isinstance(e, Literal):
            if e.chars not in tokens_by_image:
                raise ValueError("in {} production {}: undeclared token \"{}\"".format(nt, i, e.chars))
            return e.chars
        else:
            assert isinstance(e, str), e.__class__.__name__
            if e in nonterminals:
                return e
            elif e in tokens_by_name:
                image = tokens_by_name[e]
                if image is not None:
                    return image
                return e
            else:
                raise ValueError("in {} production {}: undeclared symbol {}".format(nt, i, e))

    out = {nt: [] for nt in nonterminals}
    for nt, rhs_list in nonterminals.items():
        for i, p in enumerate(rhs_list):
            out_rhs = [check_element(nt, i, e) for e in p.body]
            out[nt].append(p.copy_with(body=out_rhs))

    return (tokens, out, goal_nts)


def load_grammar(filename):
    with open(filename) as f:
        text = f.read()
    parser = parse_pgen_generated.Parser(builder=AstBuilder())
    lexer = pgen_lexer(parser, filename=filename)
    lexer.write(text)
    result = lexer.close()
    tokens, nonterminals, goals = check_grammar(result)
    variable_terminals = [name for name, image in tokens if image is None]
    return Grammar(nonterminals,
                   goal_nts=goals,
                   variable_terminals=variable_terminals)


def regenerate():
    import sys
    gen.generate_parser(sys.stdout, pgen_grammar)


if __name__ == '__main__':
    if sys.argv[1:] == ['--regenerate']:
        regenerate()
    else:
        print("usage: python -m jsparagus.parse_pgen --regenerate")
        sys.exit(1)

Messung V0.5
C=95 H=89 G=91

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge