def solve(file, verbose): simple_parser = ParserPEG(simple_grammar, root_rule_name='expr') advanced_parser = ParserPEG(advanced_grammar, root_rule_name='expr') simple_sum = 0 advanced_sum = 0 for line in file: parse_tree = simple_parser.parse(line) simple_sum += visit_parse_tree(parse_tree, SimpleVisitor()) parse_tree = advanced_parser.parse(line) advanced_sum += visit_parse_tree(parse_tree, AdvancedVisitor()) print('Part 1:', simple_sum) print('Part 2:', advanced_sum)
def test_issue_22(): """ Infinite recursion during resolving of a grammar given in a clean PEG notation. """ current_dir = os.path.dirname(__file__) grammar1 = open(os.path.join(current_dir, 'grammar1.peg')).read() parser1 = ParserPEG(grammar1, 'belang') parser1.parse('a [0]') parser1.parse('a (0)') grammar2 = open(os.path.join(current_dir, 'grammar2.peg')).read() parser2 = ParserPEG(grammar2, 'belang', debug=True) parser2.parse('a [0](1)[2]')
class ParserCantusText(): def __init__(self, grammarPath: str = GRAMMAR_PATH, root: str = 'text', **kwargs) -> None: """Initialize a Cantus Text parser. Parameters ---------- grammarPath : str, optional Path to the PEG grammar file, defaults to ``cantus/cantus_text.peg`` root : str, optional Root element of the parser, by default 'text' **kwargs Other keywords are passed to :class:`ParserPeg`. """ if not os.path.exists(grammarPath): raise Exception(f'Grammar file ({ grammarPath }) does not exist') with open(grammarPath, 'r') as handle: grammar = handle.read() self.parser = ParserPEG(grammar, root, skipws=False, **kwargs) def parse(self, text: str, debug: bool = True): # TODO docstring if not type(text) == str: return None return self.parser.parse(text)
def main(debug=False): # First we will make a parser - an instance of the calc parser model. # Parser model is given in the form of PEG notation therefore we # are using ParserPEG class. Root rule name (parsing expression) is "calc". parser = ParserPEG(calc_grammar, "document", debug=debug) filename = sys.argv[1] with open(filename) as file: contents = file.read() # An expression we want to evaluate input_expr = "<tag>dgdg</tag>" input_expr = contents # Then parse tree is created out of the input_expr expression. parse_tree = parser.parse(input_expr) #result = parser.getASG(sem_actions) #print( result ) print( parse_tree ) if debug: # getASG will start semantic analysis. # In this case semantic analysis will evaluate expression and # returned value will be evaluated result of the input_expr expression. # Semantic actions are supplied to the getASG function. print("{} = {}".format(input_expr, result))
def main(debug=False): # First we will make a parser - an instance of the calc parser model. # Parser model is given in the form of PEG notation therefore we # are using ParserPEG class. Root rule name (parsing expression) is "calc". parser = ParserPEG(calc_grammar, "document", debug=debug) filename = sys.argv[1] with open(filename) as file: contents = file.read() # An expression we want to evaluate input_expr = "<tag>dgdg</tag>" input_expr = contents # Then parse tree is created out of the input_expr expression. parse_tree = parser.parse(input_expr) #result = parser.getASG(sem_actions) #print( result ) print(parse_tree) if debug: # getASG will start semantic analysis. # In this case semantic analysis will evaluate expression and # returned value will be evaluated result of the input_expr expression. # Semantic actions are supplied to the getASG function. print("{} = {}".format(input_expr, result))
def main(debug=False): # Grammar is defined using textual specification based on PEG language. # Load grammar form file. calc_grammar = open(os.path.join(os.path.dirname(__file__), 'calc.peg'), 'r').read() # First we will make a parser - an instance of the calc parser model. # Parser model is given in the form of PEG notation therefore we # are using ParserPEG class. Root rule name (parsing expression) is "calc". parser = ParserPEG(calc_grammar, "calc", debug=debug) # An expression we want to evaluate input_expr = "-(4-1)*5+(2+4.67)+5.89/(.2+7)" # Then parse tree is created out of the input_expr expression. parse_tree = parser.parse(input_expr) # The result is obtained by semantic evaluation using visitor class. # visit_parse_tree will start semantic analysis. # In this case semantic analysis will evaluate expression and # returned value will be evaluated result of the input_expr expression. result = visit_parse_tree(parse_tree, CalcVisitor(debug=debug)) # Check that result is valid assert (result - -7.51194444444) < 0.0001 print("{} = {}".format(input_expr, result))
def parse(filename, debug=False): with open(filename) as file: contents = file.read() parser = ParserPEG(calc_grammar, "start", True) parse_tree = parser.parse(contents) visitor = Visitor(debug=debug) result = visit_parse_tree(parse_tree, visitor ) #Try to get if we found anything or not if ( visitor.functions or visitor.classes): print (visitor.namespace ) return visitor print ("Empty") return None
def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('-d', '--debug', action='store_true', default=False, help='Debug Arpeggio parser') parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Increase output verbosity') parser.add_argument('--no-order', action='store_true', default=False, help='Do not use OrderedDict') parser.add_argument('--no-visit', action='store_true', default=False, help='Do not visit the parsed tree') parser.add_argument('--rule', default='m_source_file', help='Root rule name') parser.add_argument('source_file', help='Source file to parse') global args args = parser.parse_args() logging.basicConfig(level=logging.DEBUG if args.verbose or args.debug else logging.WARNING, stream=sys.stdout) with open(args.source_file) as source_file: source_code = source_file.read() log.debug('Source file "{}" was read with success.'.format(args.source_file)) with open(m_grammar_file_path) as m_grammar_file: m_grammar = m_grammar_file.read() global m_parser m_parser = ParserPEG(m_grammar, args.rule, debug=args.debug, reduce_tree=False) log.debug('M language clean-PEG grammar was parsed with success.') parse_tree = m_parser.parse(source_code) log.debug('Source file "{}" was parsed with success.'.format(args.source_file)) if not args.no_visit: result = visit_parse_tree(parse_tree, MLanguageVisitor(debug=args.debug)) print(json.dumps(result)) return 0
def construct( arpeg_node ) : with open( "apl_grammar.txt", "rt", encoding='utf8' ) as f_in : funpy_grammar = f_in.read() parser = ParserPEG(funpy_grammar, "program", reduce_tree=True, debug=1) parser.debug = 1 #def test( parser ) : #parser.parse("R") #result = parser.parse("⌽A") OK #result = parser.parse("⌽[1]A") # OK result = parser.parse("⊖⌽A") # OK #result = parser.parse("") #result = parser.parse("") #result = parser.parse("") #result = parser.parse("") #result = parser.parse("") #result = parser.parse("") #result = parser.parse("") #result = parser.parse("") #result = parser.parse("") result
def parse(input_expr, context, debug=False): with open(os.path.join(os.path.dirname(__file__), 'matrip.peg'), 'r') as f: grammar = f.read() parser = ParserPEG(grammar, "matrip", debug=debug) parse_tree = parser.parse(input_expr) visitor = MatripVisitor(debug=debug) visit_parse_tree(parse_tree, visitor) return generate_base_table(visitor.measures, visitor.expressions, context)
def runSmurf(program): parser = ParserPEG(grammar, "program", "comment", debug=False) parse_tree = parser.parse(program) ast = visit_parse_tree(parse_tree, NodeVisitor(debug=False)) ast.accept(Interpreter()) # runSmurf(""" # let a = 5, b = 4 print(a+b) # """)
def test_regex_with_empty_successful_match_in_repetition(): grammar = \ """ rule = (subexpression)+ subexpression = r'^.*$' """ parser = ParserPEG(grammar, "rule") parsed = parser.parse("something simple") assert parsed.rule_name == "rule" assert parsed.subexpression.rule_name == "subexpression"
def test_issue_16(): parser = ParserPEG(grammar, "calc", skipws=False) input_expr = """public function __construct( )""" parse_tree = parser.parse(input_expr) # Do semantic analysis. Do not use default actions. asg = parser.getASG(sem_actions=sem_actions, defaults=False) assert asg
def runGrammar(program): parser = ParserPEG(grammar, "program", "comment", debug=False) tree = parser.parse(program) ast = visit_parse_tree(tree, VisitorClass(debug=False)) ast.accept(Interpreter()) # runGrammar(""" # let f = fn (a) { a + 1 } # print(f(3)) # """)
def solve(file, verbose): parser = ParserPEG(grammar, root_rule_name='rules') parse_tree = parser.parse(file.read()) rules = visit_parse_tree(parse_tree, BagVisitor()) graph = nx.DiGraph() for rule in rules: for bag in rule.contains: graph.add_edge(rule.bag.name, bag.name, quantity=bag.quantity) print('Part 1:', len(nx.ancestors(graph, 'shiny gold'))) print('Part 2:', count_bags(graph, 'shiny gold'))
def main(debug=False): filename = sys.argv[1] #debug = bool(sys.argv[2]) with open(filename) as file: contents = file.read() #print (contents) # # An expression we want to evaluate input_expr = """class Application extends Container implements HttpKernelInterface, TerminableInterface, ResponsePreparerInterface { """ # input_expr = input input_expr = contents if not input_expr: return None # First we will make a parser - an instance of the calc parser model. # Parser model is given in the form of PEG notation therefore we # are using ParserPEG class. Root rule name (parsing expression) is "calc". parser = ParserPEG(calc_grammar, "start", True) # Then parse tree is created out of the input_expr expression. parse_tree = parser.parse(input_expr) visitor = Visitor(debug=debug) result = visit_parse_tree(parse_tree, visitor ) print (visitor.namespace ) #print (visitor.classes ) #print (visitor.functions ) # analyseASG( parser, input, Visitor(), True, False ) # Then parse tree is created out of the input_expr expression. #parse_tree = parser.parse(input_expr) #result = parser.getASG(sem_actions) #print( parse_tree ) #print( result ) if debug: # getASG will start semantic analysis. # In this case semantic analysis will evaluate expression and # returned value will be evaluated result of the input_expr expression. # Semantic actions are supplied to the getASG function. print("{} = {}".format(input_expr, result))
def parse(input_expr): """ @param input_expr type str @return calcVisitor type CalcVisitor """ parser = ParserPEG(calc_grammar, "calc") parse_tree = parser.parse(input_expr) calcVisitor = CalcVisitor() visit_parse_tree(parse_tree, calcVisitor) return calcVisitor
class ParserDSPL: def __init__(self, grammar, root="program", dbg=False): self.parser = ParserPEG(grammar, root, comment_rule_name=None, debug=dbg, reduce_tree=True) self.parser.autokwd = True def parse(self, input: str, dbg=False): # === LEXING / PARSING ================================================= try: parse_tree = self.parser.parse(input) except NoMatch as e: print("syntax error at: (Ln {}, Col {})".format(e.line, e.col)) quit() # === SEMANTIC ANALYSIS ================================================ return visit_parse_tree(parse_tree, Visitor(debug=dbg))
def solve(file, verbose): parser = ParserPEG(grammar, root_rule_name='passports', skipws=False) parse_tree = parser.parse(file.read()) required = {'byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'} valid_keys = 0 valid_strict = 0 schema = PassportSchema() for passport in visit_parse_tree(parse_tree, PassportVisitor()): if required <= passport.keys(): valid_keys += 1 if not schema.validate(passport): valid_strict += 1 print('Part 1:', valid_keys) print('Part 2:', valid_strict)
def main(debug=False): # First we will make a parser - an instance of the calc parser model. # Parser model is given in the form of PEG notation therefore we # are using ParserPEG class. Root rule name (parsing expression) is "calc". parser = ParserPEG(calc_grammar, "calc", debug=debug) # An expression we want to evaluate input_expr = "-(4-1)*5+(2+4.67)+5.89/(.2+7)" # Then parse tree is created out of the input_expr expression. parse_tree = parser.parse(input_expr) result = visit_parse_tree(parse_tree, CalcVisitor(debug=debug)) # visit_parse_tree will start semantic analysis. # In this case semantic analysis will evaluate expression and # returned value will be evaluated result of the input_expr expression. print("{} = {}".format(input_expr, result))
def main(debug=False): # First we will make a parser - an instance of the CVS parser model. # Parser model is given in the form of clean PEG description therefore we # are using ParserPEG class from arpeggio.clenapeg. Grammar is loaded from # csv.peg file Skipping of whitespace will be done only for tabs and # spaces. Newlines have semantics in csv files. They are used to separate # records. current_dir = os.path.dirname(__file__) csv_grammar = open(os.path.join(current_dir, 'csv.peg'), 'r').read() parser = ParserPEG(csv_grammar, 'csvfile', ws='\t ', debug=debug) # Creating parse tree out of textual input test_data = open(os.path.join(current_dir, 'test_data.csv'), 'r').read() parse_tree = parser.parse(test_data) # Create list of lists using visitor csv_content = visit_parse_tree(parse_tree, CSVVisitor()) print("This is a list of lists with the data from CSV file.") pp = pprint.PrettyPrinter(indent=4) pp.pprint(csv_content)
def main(debug=False): # First we will make a parser - an instance of the calc parser model. # Parser model is given in the form of PEG notation therefore we # are using ParserPEG class. Root rule name (parsing expression) is "calc". parser = ParserPEG(calc_grammar, "calc", True) # An expression we want to evaluate input_expr = "-(4-1)*5+(2+4.67)+5.89/(.2+7)" # Then parse tree is created out of the input_expr expression. parse_tree = parser.parse(input_expr) result = parser.getASG(sem_actions) if debug: # getASG will start semantic analysis. # In this case semantic analysis will evaluate expression and # returned value will be evaluated result of the input_expr expression. # Semantic actions are supplied to the getASG function. print("{} = {}".format(input_expr, result))
def main(debug=False): current_dir = os.path.dirname(__file__) # Load grammar robot_grammar = open(os.path.join(current_dir, 'robot.peg')).read() # First we will make a parser - an instance of the robot parser model. # Parser model is given in the form of PEG specification therefore we # are using ParserPEG class. parser = ParserPEG(robot_grammar, 'robot', debug=debug) # Load program code robot_program = open(os.path.join(current_dir, 'program.rbt')).read() # We create a parse tree out of textual input parse_tree = parser.parse(robot_program) # visit_parse_tree will start semantic analysis. # In this case semantic analysis will evaluate expression and # returned value will be the final position of the robot. return visit_parse_tree(parse_tree, RobotVisitor(debug=debug))
def main(): with open('java2.peg', 'r') as file: data = file.read() parser = ParserPEG(data, "java") # ok_samples = [ # "class Baz extends Korv implements Runnable, Comparable {}", # "class Bar implements Runnable, Comparable {}", # "class Korv extends Fisk {}", # "class Knas {}", # "class Foo implements Runnable {}", # "class HejA { int foo() {} }", #"class HejB { int foo(String apaB) {} }", #"class HejC { int foo(String apaC, int korvC) {} }", #"class HejD { int foo(String apaD, int korvD, Object raketD) {} }", #"class HejE { int foo() {} void bar(){} }", #"class HejF extends Knas { int foo() {} void bar(){} }", #"class HejG extends Knas implements Runnable { int foo() {} void bar(){} }", # ] # fail_samples = [ # "class {}", # "class Knas extends implements Runnable {}", # "class Foo implements {}", # ] ok_samples = [ "sampleinputs/SampleD.java", "sampleinputs/SampleB.java", "sampleinputs/SampleC.java", "sampleinputs/SampleA.java", ] for input_file in ok_samples: with open(input_file, 'r') as file: input_expr = file.read() parse_tree = parser.parse(input_expr) result = visit_parse_tree(parse_tree, CalcVisitor(debug=False)) print(str(result[0]))
def main(debug=False): # First we will make a parser - an instance of the calc parser model. # Parser model is given in the form of python constructs therefore we # are using ParserPython class. with open('calc.peg', 'r') as file: data = file.read() parser = ParserPEG(data, "calc") # An expression we want to evaluate input_expr = "-(4-1)*5+(2+4.67)+5.89/(.2+7)" # We create a parse tree out of textual input_expr parse_tree = parser.parse(input_expr) # The result is obtained by semantic evaluation using visitor class. # visit_parse_tree will start semantic analysis. # In this case semantic analysis will evaluate expression and # returned value will be evaluated result of the input_expr expression. result = visit_parse_tree(parse_tree, CalcVisitor(debug=debug)) # Check that result is valid assert (result - -7.51194444444) < 0.0001 print("{} = {}".format(input_expr, result))
return term def visit_expression(self, node, children): """ Adds or substracts terms. Term nodes will be already evaluated. """ if self.debug: print("Expression {}".format(children)) expr = children[0] for i in range(2, len(children), 2): if i and children[i - 1] == "-": expr -= children[i] else: expr += children[i] if self.debug: print("Expression = {}".format(expr)) return expr if __name__ == '__main__': debug = False calc_grammar = open('calc.peg').read() parser = ParserPEG(calc_grammar, "calc", debug=debug) input_expr = "2*(3+4)" parse_tree = parser.parse(input_expr) result = visit_parse_tree(parse_tree, CalcVisitor(debug=debug)) print(result)
class ParserGABC(): """ Class for parsing GABC (wrapper around an Arpeggio parser) Attributes: parser (arpeggio.cleanpeg.ParserPEG): The Arpeggio parser """ def __init__(self, grammarPath: str = GRAMMAR_PATH, root: str = 'file', **kwargs) -> None: """ Args: grammar_path (:obj:`str`, optional): path to the grammar file (default is gabc/gabc.peg) root (:obj:`str`, optional): the root element of the parser (default is 'file') """ if not os.path.exists(grammarPath): raise Exception(f'Grammar file ({ grammarPath }) does not exist') with open(grammarPath, 'r') as handle: grammar = handle.read() self.parser = ParserPEG(grammar, root, skipws=False, memoization=True, **kwargs) def parse(self, gabc: str, debug=False): """Parse a gabc string Args: gabc (str): The gabc string to parse Returns: arpeggio.NonTerminal: The parse tree """ _debug = self.parser.debug self.parser.debug = debug or _debug parse = self.parser.parse(gabc) if type(parse) == list and len(parse) == 0 and len(gabc) > 0: raise EmptyParseError() if parse.position_end < len(gabc): raise IncompleteParseError( f'Parsing ended at position {parse.position_end} (input length {len(gabc)})' ) self.parser.debug = _debug return parse def parseFile(self, filename: str): """Parse a gabc file Args: filename (str): The filename of the file to parse Raises: FileNotFoundError: If the passed filename does not exist Returns: arpeggio.NonTerminal: The parse tree """ if not os.path.exists(filename): raise FileNotFoundError() with open(filename, 'r') as handle: contents = handle.read() return self.parse(contents)
def try_grammer(peg): p = ParserPEG(peg, 'letters', debug=False) p.parse(""" { a b } """) p.parse(""" { b a } """)
text = self.text_string_decoder(text) return text def visit_WSP(self, node, children): if self.abc_debug: self.print_debug(node, children) return ' ' def canonify_music_code(line, text_string_decoder=None): parse_tree = parser.parse(line) return visit_parse_tree( parse_tree, ABCVisitor(text_string_decoder=text_string_decoder)) if __name__ == '__main__': # pragma: no cover import pprint import sys pp = pprint.PrettyPrinter(indent=2) result = parser.parse(sys.argv[1]) print(result) # not useful if one is interested in literal terminals pp.pprint(result) print('==================================================') v = visit_parse_tree(result, ABCVisitor(abc_debug=True)) print('==================================================') pp.pprint(v) for c in v: print(hex(ord(c)))
def solve(file, verbose): parser = ParserPEG(grammar, root_rule_name='instructions', skipws=False) parse_tree = parser.parse(file.read()) instructions = visit_parse_tree(parse_tree, CodeVisitor()) print('Part 1:', part1(instructions)) print('Part 2:', part2(instructions))
/ "(" arithmetic_expression ")" integer = "-"? r'[0-9]+' addop = '+' / '-' mulop = '*' / '/' relop = '==' / '!=' / '>=' / '>' / '<=' / '<' function_call = variable_reference "(" call_arguments ")" / "print" "(" call_arguments ")" call_arguments = (expr ("," expr)*)? function_definition = param_list brace_block param_list = "(" identifier ("," identifier)* ")" / "(" ")" brace_block = "{" code "}" """ with open(argv[1]) as file: content = file.read() parser = ParserPEG(grammar, "program", "comment", debug=False) tree = parser.parse(content) ast = visit_parse_tree(tree, SmurfVisitor(debug=False)) result = ast.accept(Interpreter())
def quality_control_edit(view, form_id, qc=None): template_name = 'admin/quality_assurance_edit.html' form = models.Form.query.filter_by(id=form_id).first_or_404() breadcrumbs = [{ 'text': _('Forms'), 'url': url_for('formsview.index') }, { 'text': _('Quality Assurance'), 'url': url_for('formsview.qc', form_id=form.id) }, form.name] if request.method == 'POST': try: postdata = json.loads(request.form.get('postdata')) quality_control = {} if 'name' in postdata and postdata['name']: # we have a quality control that should exist quality_control = next( filter(lambda c: c['name'] == postdata['name'], form.quality_checks)) if not quality_control: quality_control['name'] = generate_identifier() quality_control['description'] = postdata['description'] quality_control['criteria'] = [] parser = ParserPEG(GRAMMAR, 'qa') for condition in postdata['criteria']: formula = '{lvalue} {comparator} {rvalue}'.format(**condition) try: parser.parse(formula) # parsing succeeds so it must be good quality_control['criteria'].append({ 'lvalue': condition['lvalue'], 'comparator': condition['comparator'], 'rvalue': condition['rvalue'], 'conjunction': condition['conjunction'] }) except NoMatch: pass if 'rvalue' in quality_control: del quality_control['rvalue'] if 'lvalue' in quality_control: del quality_control['lvalue'] if 'comparator' in quality_control: del quality_control['comparator'] if form.quality_checks: for i, control in enumerate(form.quality_checks): if control['name'] == quality_control['name']: form.quality_checks[i] = quality_control break else: form.quality_checks.append(quality_control) else: form.quality_checks = [quality_control] form.save() if request.is_xhr: return 'true' else: return redirect(url_for('formsview.qc', form_id=form.id)) except ValueError: pass if qc: try: quality_check = next( filter(lambda c: c['name'] == qc, form.quality_checks)) except StopIteration: abort(404) criteria = [] if 'criteria' in quality_check: for index, criterion in enumerate(quality_check['criteria']): criteria.append({ 'lvalue': criterion['lvalue'], 'comparator': criterion['comparator'], 'rvalue': criterion['rvalue'], 'conjunction': criterion['conjunction'], 'id': str(index) }) else: criteria.append({ 'lvalue': quality_check['lvalue'], 'comparator': quality_check['comparator'], 'rvalue': quality_check['rvalue'], 'conjunction': '&&', 'id': '0' }) title = _('Edit Quality Assurance') is_new = 0 quality_control = { 'name': quality_check['name'], 'description': quality_check['description'], 'criteria': criteria } else: title = _('Add Quality Assurance') is_new = 1 quality_control = { 'name': '', 'description': '', 'criteria': [{ 'lvalue': '', 'comparator': '=', 'rvalue': '', 'conjunction': '&&', 'id': '0' }] } context = { 'title': title, 'is_new': is_new, 'breadcrumbs': breadcrumbs, 'form': form, 'participant_set': g.event.participant_set, 'location_set': g.event.location_set, 'quality_control': quality_control } return view.render(template_name, **context)
from arpeggio.cleanpeg import ParserPEG from arpeggio import visit_parse_tree from node_rules import * debug = True ws = '\t ' grammar = open( os.path.join(os.path.dirname(__file__), 'clean_grammar_test.peg'), 'r').read() parser = ParserPEG(grammar, "start", debug=False, ws=ws, comment_rule_name='Comment') input_expr = open('./test.r', 'r').read() parse_tree = parser.parse(input_expr) print(str(parse_tree)) # level = 20 # value = 5 # l = ' ' * level + 'Numeric\n' + ' ' * (level + 1) + str(value) # print(l) # exit() def extract_arr(tree): if not isinstance(tree, list): if tree: return [tree] else: return []
class ParserCalc(PTNodeVisitor): def __init__(self, parser=None): self.parser = ParserPEG(grammar, 'calc', skipws=False, ignore_case=True) def __call__(self, s): try: return visit_parse_tree(self.parser.parse(s), self.CalcVisitor(debug=False)) except Exception as e: # print(e) return None class CalcVisitor(PTNodeVisitor): def visit_calc(self, n, c): _expr = lambda ast: visit_parse_tree(ast, ParserCalc.ExpressionVisitor(debug=False)) if 'repeat' in c.results: repeat = int(c.results['repeat'][0]) if 1 < repeat <= 20: return [_expr(n) for _ in range(repeat)] else: return [_expr(n)] class ExpressionVisitor(PTNodeVisitor): def visit_roll(self, n, c): if self.debug: print('roll: %s'%(c.results)) res = c.results return roll.roll( int(res['sides'][0]), count=int(res.get('count', [1])[0]), take_size=int(res.get('take_size', [0])[0]), take_higest=res.get('take_high', []) != [] ) def visit_eval(self, n, c): if self.debug: print('eval: %s'%(c.results)) c = c.results if 'int' in c: i = int(c['int'][0]) return [str(i), i] elif 'float' in c: f = c['float'][0] return [f, float(f)] else: return c['roll'][0] def visit_factor(self, n, c): if self.debug: print('factor: %s'%(c.results)) c = c.results if 'eval' in c and 'expression' in c: print('Error "eval" and "expression"') if 'eval' in c: cc = c['eval'][0] if 'expression' in c: cc = c['expression'][0] cc[0] = '(%s)'%(cc[0]) return cc def visit_term(self, n, c): if self.debug: print('term: %s'%(c.results)) if len(c.results['factor']) == 0: print('Error 0 factors in term') return ['', None] c = c.results res = c['factor'][0] if 'mul' in c: fac = c['factor'][1:] mul = c['mul'] op = lambda x, y, o: None if x is None or y is None else x * y if o == '*' else float(x) / y if y != 0 else False for i in range(0, len(fac)): m = mul[i] f = fac[i] res[1] = op(res[1], f[1], m) if not res[1]: res[1] = None f[0] = bold(f[0]) res[0] += '%s%s'%(m, f[0]) return res def visit_expression(self, n, c): if self.debug: print('expression: %s'%(c.results)) if len(c.results['term']) == 0: print('Error 0 term in expr') return ['', None] c = c.results res = c['term'][0] if 'sign' in c: res = ['-%s'%(res[0]), -1 * res[1]] if 'add' in c: fac = c['term'][1:] add = c['add'] op = lambda x, y, o: None if x is None or y is None else x + y if o == '+' else x - y for i in range(0, len(fac)): a = add[i] f = fac[i] res[0] += '%s%s'%(a, f[0]) res[1] = op(res[1], f[1], a) return res def visit_calc(self, n, c): if self.debug: print('calc: %s'%(c.results)) c = c.results if 'roll' in c: return c['roll'][0] if 'expression' in c: return c['expression'][0] return [None, None]
relop = '==' / '!=' / '>=' / '>' / '<=' / '<' primary = integer / function_call / variable_reference / "(" arithmetic_expression ")" function_call = variable_reference "(" call_arguments ")" / "print" "(" call_arguments ")" call_arguments = (expr ("," expr)*)? function_definition = param_list brace_block param_list = "(" identifier ("," identifier)* ")" / "(" ")" brace_block = "{" code "}" """ with open(argv[1]) as file: filePath = file.read() #PARSERPG WENT ALONG BEST WITH MY SYTAX FOR THE GRAMMER #PARSERS THROUGHT THE WHOLE SYTAX parser = ParserPEG(grammer, "program", "comment") #THIS IS THE PARSING FOR THE FILE parse_tree = parser.parse(filePath) #THIS IS THE BUILDING OF ASTTREE ast = visit_parse_tree(parse_tree, Visitor()) #CALLS INTERPRETER ast.accept(Interpreter())
class ParserCantusVolpiano(): def __init__(self, grammarPath = None, root: str = 'volpiano', strict: bool = False, **kwargs) -> None: """Initialize a Cantus Volpiano parser. Parameters ---------- grammarPath : str, optional Path to the PEG grammar file, defaults to ``grammars/cantus_volpiano.peg`` root : str, optional Root element of the parser, by default 'volpiano' strict : bool, optional Whether to parse in strict mode or not. In strict mode, exceptions are raised whenever volpiano strings deviate from the standard syntax. In non-strict mode, some deviations will be automatically corrected. See :meth:`ParserCantusVolpiano.preprocess` for details. By default True **kwargs Other keywords are passed to :class:`ParserPeg`. """ if grammarPath == None: grammarPath = GRAMMAR_PATH if not os.path.exists(grammarPath): raise Exception(f'Grammar file ({ grammarPath }) does not exist') with open(grammarPath, 'r') as handle: grammar = handle.read() self.strict = strict self.parser = ParserPEG(grammar, root, skipws=False, **kwargs) def preprocess(self, volpiano: str, strict: bool = None): """Checks and possibly corrects the volpiano string before parsing. If the parser operates in strict mode (``strict=True``) all deviations from the standard syntax result in parser exceptions. Otherwise, the preprocessor tries to correct common mistakes and variations. Volpiano should start with a clef: >>> parser = ParserCantusVolpiano(strict=False) >>> parser.preprocess('1---g') '1---g' >>> parser.preprocess('f-g') Traceback (most recent call last): ... chant21.parser_cantus_volpiano.ClefError: Missing clef: the volpiano does not start with a clef (1 or 2) Generally the clef should be followed by 3 hyphens. However, a number of chants in Cantus use an alternative hyphenation where words appear to be separated by 2 hyphens, and syllables by 1. Chant21 will try to correct this alternative hyphenation: >>> parser.preprocess('1--fg-f--h') '1---fg--f---h' Sometimes the clef suggests the alternative hyphenation (``1--f...``), but later in the chant we find a word boundary ``---``. In that case the clef hyphenation is corrected (or a HyphenationError is raised in strict mode): >>> parser.preprocess('1--f-g---h--f') '1---f-g---h--f' The use of 4 or 5 hyphens is not supported; those are replaced by a word boundary: >>> parser.preprocess('1---a----b-----c--d') '1---a---b---c--d' One situation where you may find more dashes is in the missing pitches fragment ``6------6``. When more than 6 hyphens are used between the 6s, those are removed: >>> parser.preprocess('1---6---------6') '1---6------6' Missing pitches often appear close to page breaks, and these are marked directly before/after the missing pitches. There should be three hyphens before and after all that: >>> parser.preprocess('1---a--6------67--b') '1---a---6------67---b' Sometimes the wrong barlines are used: ``33`` instead of ``4`` for a double barline; a thick barline ``5`` instead of the double barline ``4``. Barlines should also be surrounded by 3 hyphens on both sides: >>> parser.preprocess('1---f-33-g') '1---f---4---g' >>> parser.preprocess('1---5') '1---4' Parameters ---------- volpiano : str The volpianos tring strict : bool, optional Whether to operate in strict mode or not. In strict mode, exceptions are raised whenever volpiano strings deviate from the standard syntax. In non-strict mode, some deviations will be automatically corrected. The parameter defaults to the class' ``.strict`` attribute. Returns ------- str A preprocessed Volpiano string. Raises ------ ClefError A missing clef HyphenationError Raised when there is a problem with the hyphenation. UnsupportedCharacterError Raised when the volpiano string contains non-volpiano characters. BarlineError Raised when for example the wrong barline symbols are used """ if strict is None: strict = self.strict if volpiano[0] not in '12': raise ClefError('Missing clef: the volpiano does not start with a clef (1 or 2)') if re.match('^[12]-?[^-]', volpiano): raise HyphenationError('Invalid clef hyphenation: chant should start with 1-- or 1---') # Mixed hyphenation: start with 1-- (2 hyphens), but still contains word # boundaries (3 hyphens). has_standard_hyphenation = volpiano.startswith('1---') or volpiano.startswith('2---') if not has_standard_hyphenation and re.match('.*[^-]---[^-]', volpiano): if strict: raise HyphenationError('Mixed hyphenation: starts with 1--, but contains word boundaries') else: # Todo debug volpiano = volpiano[0] + '---' + volpiano[3:] elif not has_standard_hyphenation: if strict: raise HyphenationError('Chant contains no word boundaries') else: volpiano = (volpiano.replace('--', '$$$') .replace('-', '--') .replace('$$$', '---')) # 4 or 5 hyphens are used as a separator: that's not supported. # If not strict, replace by word boundary if re.match('.*[^-]-{4,5}[^-]', volpiano): if strict: raise HyphenationError('contains boundaries with 4 or 5 hyphens') else: def replacer(match): return re.sub('-+', '---', match.group()) volpiano = re.sub('[^-]-{4,5}[^-]', replacer, volpiano) # Repeat to also replace neighbouring matches volpiano = re.sub('[^-]-{4,5}[^-]', replacer, volpiano) # Missing pitches with more than 6 hyphens if re.match('.*6-{7,}6', volpiano): if strict: raise HyphenationError('Too many hyphens in missing pitches') else: volpiano = re.sub('6-{7,}6', '6------6', volpiano) # Missing pitches should be transcribed as ---6------6---: preceded # and followed by a word boundary (3 hyphens) if re.match('.*[^-]--7*6------6', volpiano) or re.match('.*6------67*--[^-]', volpiano): if strict: raise HyphenationError('Missing pitches preceded/followed by syllable boundary') else: def replacer(match): vol = match.group() if vol[2] != '-': vol = '-' + vol if vol[-3] != '-': vol += '-' return vol volpiano = re.sub('-+7*6------67*-+', replacer, volpiano) if '.' in volpiano: if strict: raise UnsupportedCharacterError('The dot (.) is not supported, use hyphens instead.') else: volpiano = volpiano.replace('.', '') # Double barlines written as '33' (two single barlines) rather than 4 if '33' in volpiano: if strict: raise BarlineError('Use "4" for a double barline, not "33"') else: volpiano = volpiano.replace('33', '4') # Thick barlines are not used. if '5' in volpiano: if strict: raise BarlineError('Use "4" for a double barline, not "5"') else: volpiano = volpiano.replace('5', '4') # Barlines preceded by too few hyphens if has_standard_hyphenation and re.match('.*[^-]-{1,2}[34]', volpiano): if strict: raise HyphenationError('Barlines should be preceded by 3 hyphens') else: def replacer(match): vol = match.group() return vol[0] + '---' + vol[-1] volpiano = re.sub('[^-]-{1,2}[34]', replacer, volpiano) # Barlines followed by too few hyphens if has_standard_hyphenation and re.match('.*[34]-{1,2}[^-]', volpiano): if strict: raise HyphenationError('Barlines should be followed by 3 hyphens') else: def replacer(match): vol = match.group() return vol[0] + '---' + vol[-1] volpiano = re.sub('[34]-{1,2}[^-]', replacer, volpiano) # TODO the same problem occurs for non-standard hyphenation. Perhaps add this? return volpiano def parse(self, volpiano: str, strict = None): """Parse a Cantus Volpiano string. >>> parser = ParserCantusVolpiano() >>> parse = parser.parse('1---a-b--c---d-e---4') >>> type(parse) <class 'arpeggio.NonTerminal'> Parameters ---------- volpiano : str The volpiano string to be parsed strict : bool, optional Whether to parse in strict mode or not. In strict mode, exceptions are raised whenever volpiano strings deviate from the standard syntax. In non-strict mode, some deviations will be automatically corrected. See :meth:`ParserCantusVolpiano.preprocess` for details. By default True Returns ------- arpeggio.NonTerminal The parse tree """ volpiano = self.preprocess(volpiano, strict=strict) return self.parser.parse(volpiano)