#!/usr/bin/env python3 # -*- coding: utf-8 -*- """comment.py: Hog 4 comment macro interpreter and OSC bridge.""" __author__ = "Kevin Matz" __copyright__ = "Copyright 2018, Company 235, LLC" __credits__ = ["Kevin Matz"] __license__ = "MIT" __version__ = "3.9" __maintainer__ = "Kevin Matz" __email__ = "kevin@company235.com" __status__ = "Prototype" import configparser import logging import sys from antlr4 import CommonTokenStream from antlr4 import InputStream from antlr4 import ParseTreeWalker from antlr4.error.ErrorListener import ErrorListener from pythonosc import udp_client try: # include reletive path imports when a module from .CommentMacroLexer import CommentMacroLexer from .CommentMacroParser import CommentMacroParser from .OscCommentMacroListener import OscCommentMacroListener except ImportError: # include directly when called directly from CommentMacroLexer import CommentMacroLexer from CommentMacroParser import CommentMacroParser from OscCommentMacroListener import OscCommentMacroListener # define an error listener that raises SyntaxError exceptions class SyntaxErrorListener(ErrorListener): def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): raise SyntaxError("line "+str(line)+":"+str(column)+" "+msg) # setup logging logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) ch = logging.StreamHandler() # create console handler and ch.setLevel(logging.INFO) # set console log level to INFO logger.addHandler(ch) # add console log handler # empty server dictionary servers = {} # open config file config = configparser.ConfigParser(allow_no_value=True) config.read('server.cfg') # set up each hog device for name in config.get('network', 'hogs').split(','): try: # move to config section server = config[name.strip().strip('\"')] # read settings ip = server.get("ip", "10.0.0.100") port = server.getint("port", 7001) net = server.getint("net", 1) # osc clients are added to the dictionary with the net # as the key logger.info("Adding Hog device at net# " + str(net)) servers[net] = udp_client.SimpleUDPClient(ip, port) except KeyError as e: print('Error configuring net#', net, e) continue # clear temp variables off the stack try: del ip, port, net del server, config except NameError as e: print('failed to release memory', e) # init reusable walker and listener walker = ParseTreeWalker() listener = OscCommentMacroListener(servers) # main handler for processing input def comment(text): # force upper case text = text.upper() # generate text stream input_stream = InputStream(text) # lex the text stream lexer = CommentMacroLexer(input_stream) # get token stream from lexer stream = CommonTokenStream(lexer) # parse the token steam parser = CommentMacroParser(stream) # attach an error handler to the parser parser._listeners.append(SyntaxErrorListener()) try: # get tree from parser tree = parser.prog() # walk the tree walker.walk(listener, tree) except SyntaxError as e: logger.debug(e) # antlr internal listener prints the error # # log it to the debug logger anyway # handle user input if run directly if __name__ == '__main__': if len(sys.argv) > 1: # look for macros passed as arguments logger.debug("found macro at argv[1]") comment(sys.argv[1]) else: # for input history and line editing import readline # be an interactive shell while True: # get user input try: text = input("comment# ") except (KeyboardInterrupt, EOFError): text = 'exit' print(text) # catch exit keyword if text.lower() == 'exit': break # exec user input comment(text)