ArithmeticCompiler.py 7.1 KB
Newer Older
1
#!/usr/bin/python3
eckhart's avatar
eckhart committed
2 3 4 5 6 7 8 9 10 11 12

#######################################################################
#
# SYMBOLS SECTION - Can be edited. Changes will be preserved.
#
#######################################################################


from functools import partial
import os
import sys
eckhart's avatar
eckhart committed
13 14 15

sys.path.extend(['../../', '../', './'])

eckhart's avatar
eckhart committed
16 17 18 19 20 21
try:
    import regex as re
except ImportError:
    import re
from DHParser import logging, is_filename, load_if_file, \
    Grammar, Compiler, nil_preprocessor, PreprocessorToken, \
di68kap's avatar
di68kap committed
22 23
    Lookbehind, Lookahead, Alternative, Pop, Token, Synonym, AllOf, SomeOf, Unordered, \
    Option, NegativeLookbehind, OneOrMore, RegExp, Retrieve, Series, Capture, \
eckhart's avatar
eckhart committed
24 25 26
    ZeroOrMore, Forward, NegativeLookahead, mixin_comment, compile_source, \
    last_value, counterpart, accumulate, PreprocessorFunc, \
    Node, TransformationFunc, TransformationDict, \
eckhart's avatar
eckhart committed
27
    traverse, remove_children_if, is_anonymous, Whitespace, \
eckhart's avatar
eckhart committed
28
    reduce_single_child, replace_by_single_child, replace_or_reduce, remove_whitespace, \
29
    remove_expendables, remove_empty, remove_tokens, flatten, is_insignificant_whitespace, \
eckhart's avatar
eckhart committed
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
    is_empty, is_expendable, collapse, replace_content, WHITESPACE_PTYPE, TOKEN_PTYPE, \
    remove_nodes, remove_content, remove_brackets, replace_parser, \
    keep_children, is_one_of, has_content, apply_if, remove_first, remove_last, \
    remove_anonymous_empty, keep_nodes, traverse_locally, strip


#######################################################################
#
# PREPROCESSOR SECTION - Can be edited. Changes will be preserved.
#
#######################################################################

def ArithmeticPreprocessor(text):
    return text, lambda i: i

def get_preprocessor() -> PreprocessorFunc:
    return ArithmeticPreprocessor


#######################################################################
#
# PARSER SECTION - Don't edit! CHANGES WILL BE OVERWRITTEN!
#
#######################################################################

class ArithmeticGrammar(Grammar):
eckhart's avatar
eckhart committed
56
    r"""Parser for an Arithmetic source file.
eckhart's avatar
eckhart committed
57 58 59 60 61
    """
    constant = Forward()
    digit = Forward()
    expression = Forward()
    variable = Forward()
62
    source_hash__ = "43a6a760b591f9409b06f3c18a3b5ea5"
63
    static_analysis_pending__ = False
eckhart's avatar
eckhart committed
64
    parser_initialization__ = ["upon instantiation"]
eckhart's avatar
eckhart committed
65
    resume_rules__ = {}
eckhart's avatar
eckhart committed
66
    COMMENT__ = r''
di68kap's avatar
di68kap committed
67
    WHITESPACE__ = r'\s*'
68
    WSP_RE__ = mixin_comment(whitespace=WHITESPACE__, comment=COMMENT__)
di68kap's avatar
di68kap committed
69
    wsp__ = Whitespace(WSP_RE__)
eckhart's avatar
eckhart committed
70
    test = Series(digit, constant, variable)
di68kap's avatar
di68kap committed
71
    digit.set(Alternative(Series(Token("0"), wsp__), Series(Token("1"), wsp__), Series(Token("..."), wsp__), Series(Token("9"), wsp__)))
eckhart's avatar
eckhart committed
72
    constant.set(Series(digit, ZeroOrMore(digit)))
di68kap's avatar
di68kap committed
73 74 75 76
    variable.set(Alternative(Series(Token("x"), wsp__), Series(Token("y"), wsp__), Series(Token("z"), wsp__)))
    factor = Alternative(constant, variable, Series(Series(Token("("), wsp__), expression, Series(Token(")"), wsp__)))
    term = Series(factor, ZeroOrMore(Series(Alternative(Series(Token("*"), wsp__), Series(Token("/"), wsp__)), factor)))
    expression.set(Series(term, ZeroOrMore(Series(Alternative(Series(Token("+"), wsp__), Series(Token("-"), wsp__)), term))))
eckhart's avatar
eckhart committed
77 78 79
    root__ = expression
    
def get_grammar() -> ArithmeticGrammar:
80
    global GLOBALS
eckhart's avatar
eckhart committed
81
    try:
82
        grammar = GLOBALS.Arithmetic_00000001_grammar_singleton
eckhart's avatar
eckhart committed
83
    except AttributeError:
84
        GLOBALS.Arithmetic_00000001_grammar_singleton = ArithmeticGrammar()
85
        if hasattr(get_grammar, 'python_src__'):
86 87
            GLOBALS.Arithmetic_00000001_grammar_singleton.python_src__ = get_grammar.python_src__
        grammar = GLOBALS.Arithmetic_00000001_grammar_singleton
eckhart's avatar
eckhart committed
88 89 90 91 92 93 94 95 96 97 98
    return grammar


#######################################################################
#
# AST SECTION - Can be edited. Changes will be preserved.
#
#######################################################################

Arithmetic_AST_transformation_table = {
    # AST Transformations for the Arithmetic-grammar
99
    "<": remove_empty,
eckhart's avatar
eckhart committed
100 101 102 103 104 105 106
    "expression": [],
    "term": [],
    "factor": [replace_or_reduce],
    "variable": [replace_or_reduce],
    "constant": [],
    "digit": [replace_or_reduce],
    "test": [],
107
    ":_Token, :_RE": reduce_single_child,
eckhart's avatar
eckhart committed
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 152 153 154 155 156
    "*": replace_by_single_child
}


def ArithmeticTransform() -> TransformationDict:
    return partial(traverse, processing_table=Arithmetic_AST_transformation_table.copy())

def get_transformer() -> TransformationFunc:
    global thread_local_Arithmetic_transformer_singleton
    try:
        transformer = thread_local_Arithmetic_transformer_singleton
    except NameError:
        thread_local_Arithmetic_transformer_singleton = ArithmeticTransform()
        transformer = thread_local_Arithmetic_transformer_singleton
    return transformer


#######################################################################
#
# COMPILER SECTION - Can be edited. Changes will be preserved.
#
#######################################################################

class ArithmeticCompiler(Compiler):
    """Compiler for the abstract-syntax-tree of a Arithmetic source file.
    """

    def on_expression(self, node):
        return node

    # def on_term(self, node):
    #     return node

    # def on_factor(self, node):
    #     return node

    # def on_variable(self, node):
    #     return node

    # def on_constant(self, node):
    #     return node

    # def on_digit(self, node):
    #     return node

    # def on_test(self, node):
    #     return node


eckhart's avatar
eckhart committed
157
def get_compiler() -> ArithmeticCompiler:
eckhart's avatar
eckhart committed
158 159 160 161
    global thread_local_Arithmetic_compiler_singleton
    try:
        compiler = thread_local_Arithmetic_compiler_singleton
    except NameError:
eckhart's avatar
eckhart committed
162
        thread_local_Arithmetic_compiler_singleton = ArithmeticCompiler()
eckhart's avatar
eckhart committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
        compiler = thread_local_Arithmetic_compiler_singleton
    return compiler


#######################################################################
#
# END OF DHPARSER-SECTIONS
#
#######################################################################


def compile_src(source, log_dir=''):
    """Compiles ``source`` and returns (result, errors, ast).
    """
    with logging(log_dir):
        compiler = get_compiler()
        cname = compiler.__class__.__name__
        log_file_name = os.path.basename(os.path.splitext(source)[0]) \
            if is_filename(source) < 0 else cname[:cname.find('.')] + '_out'
        result = compile_source(source, get_preprocessor(),
                                get_grammar(),
                                get_transformer(), compiler)
    return result


if __name__ == "__main__":
    if len(sys.argv) > 1:
        file_name, log_dir = sys.argv[1], ''
        if file_name in ['-d', '--debug'] and len(sys.argv) > 2:
            file_name, log_dir = sys.argv[2], 'LOGS'
        result, errors, ast = compile_src(file_name, log_dir)
        if errors:
            cwd = os.getcwd()
            rel_path = file_name[len(cwd):] if file_name.startswith(cwd) else file_name
            for error in errors:
                print(rel_path + ':' + str(error))
            sys.exit(1)
        else:
            print(result.as_xml() if isinstance(result, Node) else result)
    else:
        print("Usage: ArithmeticCompiler.py [FILENAME]")