import Oif


try:
    import os, gettext
    locale_dir = os.path.split(__file__)[0]
    gettext.install('4Suite', locale_dir)
except (ImportError, AttributeError, IOError):
    def _(msg):
        return msg

SYNTAX_ERR_MSG = _("'%.0sSyntax error at or near '%s' Line: %d, Production Number: %s")
INTERNAL_ERR_MSG = _("%.0sInternal error in processing at or near '%s', Line: %d, Production Number: %s, Exception: %s")

class SyntaxException(Exception):
    def __init__(self, source, lineNum, location, prodNum):
        Exception.__init__(self, SYNTAX_ERR_MSG%(source, location, lineNum, prodNum))
        self.source = source
        self.lineNum = lineNum
        self.loc = location
        self.prodNum = prodNum

class InternalException(Exception):
    def __init__(self, source, lineNum, location, prodNum, exc, val, tb):
        Exception.__init__(self, INTERNAL_ERR_MSG%(source, location, lineNum, prodNum, exc))
        self.source = source
        self.lineNum = lineNum
        self.loc = location
        self.prodNum = prodNum
        self.errorType = exc
        self.errorValue = val
        self.errorTraceback = tb


class OifParserBase:
    def __init__(self):
        self.initialize()

    def initialize(self):
        self.results = None
        self.__stack = []
        Oif.cvar.g_prodNum = "-1"
        Oif.cvar.g_errorOccured = 0

    def parse(self,st):
        self.initialize()
        Oif.my_Oifparse(self,st)
        if Oif.cvar.g_errorOccured == 1:
            raise SyntaxException(
                st,
                Oif.cvar.lineNum,
                Oif.cvar.g_errorLocation,
                Oif.cvar.g_prodNum)
        if Oif.cvar.g_errorOccured == 2:
            raise InternalException(
                st,
                Oif.cvar.lineNum,
                Oif.cvar.g_errorLocation,
                Oif.cvar.g_prodNum,
                Oif.cvar.g_errorType,
                Oif.cvar.g_errorValue,
                Oif.cvar.g_errorTraceback)
        return self.__stack

    def pop(self):
        if len(self.__stack):
            rt = self.__stack[-1]
            del self.__stack[-1]
            return rt
        self.raiseException("Pop with 0 stack length")

    def push(self,item):
        self.__stack.append(item)

    def empty(self):
        return len(self.__stack) == 0

    def size(self):
        return len(self.__stack)

    def raiseException(self, message):
        raise Exception(message + "\n" +
                        "EBNF ProductionNumber: " +
                        str(Oif.cvar.g_prodNum)
                        )

    ### Callback methods ###

    def OIF_file(self, arg0 = None):
        print 'OIF_file called with %s ' % (str(arg0))
    def object_def_list(self, arg0 = None, arg1 = None):
        print 'object_def_list called with %s %s ' % (str(arg0), str(arg1))
    def object_def(self, arg0 = None, arg1 = None, arg2 = None, arg3 = None, arg4 = None, arg5 = None):
        print 'object_def called with %s %s %s %s %s %s ' % (str(arg0), str(arg1), str(arg2), str(arg3), str(arg4), str(arg5))
    def physically_near_to(self, arg0 = None, arg1 = None, arg2 = None):
        print 'physically_near_to called with %s %s %s ' % (str(arg0), str(arg1), str(arg2))
    def initialization(self, arg0 = None):
        print 'initialization called with %s ' % (str(arg0))
    def attribute_list(self, arg0 = None, arg1 = None, arg2 = None):
        print 'attribute_list called with %s %s %s ' % (str(arg0), str(arg1), str(arg2))
    def attribute(self, arg0 = None, arg1 = None):
        print 'attribute called with %s %s ' % (str(arg0), str(arg1))
    def value_list(self, arg0 = None, arg1 = None, arg2 = None):
        print 'value_list called with %s %s %s ' % (str(arg0), str(arg1), str(arg2))
    def value(self, arg0 = None):
        print 'value called with %s ' % (str(arg0))
    def literal(self, arg0 = None):
        print 'literal called with %s ' % (str(arg0))
    def struct_value(self, arg0 = None, arg1 = None, arg2 = None):
        print 'struct_value called with %s %s %s ' % (str(arg0), str(arg1), str(arg2))
    def array_value(self, arg0 = None, arg1 = None, arg2 = None):
        print 'array_value called with %s %s %s ' % (str(arg0), str(arg1), str(arg2))
    def indexed_value_list(self, arg0 = None, arg1 = None, arg2 = None, arg3 = None):
        print 'indexed_value_list called with %s %s %s %s ' % (str(arg0), str(arg1), str(arg2), str(arg3))
    def index(self, arg0 = None):
        print 'index called with %s ' % (str(arg0))
    def collection_value(self, arg0 = None, arg1 = None, arg2 = None):
        print 'collection_value called with %s %s %s ' % (str(arg0), str(arg1), str(arg2))
    def fieldname(self, arg0 = None):
        print 'fieldname called with %s ' % (str(arg0))
    def classname(self, arg0 = None):
        print 'classname called with %s ' % (str(arg0))
    def object_tag(self, arg0 = None):
        print 'object_tag called with %s ' % (str(arg0))
    def boolean_literal(self, arg0 = None):
        print 'boolean_literal called with %s ' % (str(arg0))
    def character_literal(self, arg0 = None):
        print 'character_literal called with %s ' % (str(arg0))
    def integer_literal(self, arg0 = None):
        print 'integer_literal called with %s ' % (str(arg0))
    def float_literal(self, arg0 = None):
        print 'float_literal called with %s ' % (str(arg0))
    def string_literal(self, arg0 = None):
        print 'string_literal called with %s ' % (str(arg0))
    def scoped_name(self, arg0 = None, arg1 = None, arg2 = None):
        print 'scoped_name called with %s %s %s ' % (str(arg0), str(arg1), str(arg2))
def PrintSyntaxException(e):
    print "********** Syntax Exception **********"
    print "Exception at or near '%s'" % e.loc
    print "  Line: %d, Production Number: %s" % (e.lineNum, str(e.prodNum))

def PrintInternalException(e):
    print "********** Internal Exception **********"
    print "Exception at or near '%s'" % e.loc
    print "  Line: %d, Production Number: %s" % (e.lineNum, e.prodNum)
    print "    Exception: %s" % e.errorType
    print "Original traceback:"
    import traceback
    traceback.print_tb(e.errorTraceback)

if __name__ == "__main__":
    import sys
    p = OifParserBase()
    if len(sys.argv) == 2:
        l = open(sys.argv[1],"r").read()
    else:
        l = raw_input(">>>")
    try:
        p.parse(l)
    except InternalException, e:
        PrintInternalException(e)
    except SyntaxException, e:
        PrintSyntaxException(e)
