class Project:
    dConfig = {}
    dAddFileInfo = {'amip1sst.F'       : {'linelength':132},
                    'landmask.F'       : {'linelength':132},
                    'sstmskgh.F'       : {'linelength':132},
                    'mod_calendar.F90' : {'linelength':132},
                    'cuascn.intfb.h'   : {'format':"free"},
                    'cubasen.intfb.h'  : {'format':"free"},
                    'cubasmcn.intfb.h' : {'format':"free"},
                    'cubidiag.intfb.h' : {'format':"free"},
                    'cuctracer.intfb.h': {'format':"free"},
                    'cuddrafn.intfb.h' : {'format':"free"},
                    'cudlfsn.intfb.h'  : {'format':"free"},
                    'cudtdqn.intfb.h'  : {'format':"free"},
                    'cududvn.intfb.h'  : {'format':"free"},
                    'cududvn.intfb.h'  : {'format':"free"},
                    'cuentrn.intfb.h'  : {'format':"free"},
                    'cuflxn.intfb.h'   : {'format':"free"},
                    'cuinin.intfb.h'   : {'format':"free"},
                    'sucumfn.intfb.h'  : {'format':"free"},
                    'fcttre_new.h'     : {'format':"free", 'linelength':132},
                    'zevpmx.F':          {'linelength':132} }
    def __init__(self,sProject=None):
        self.dConfig        = Project.dConfig
        self.Cache          = Cache(nSize=10, sProject=sProject)
        self.dRecursiveTest = {}
    # --------------------------------------------------------------------------
    def FindFile(self, sFilename):
        sFullName = sFilename
        if os.access(sFullName, os.R_OK):
            return sFullName
        return None
    # --------------------------------------------------------------------------
    # Try to find a (or several) files which (might) contain a certain
    # identifier. For now this subroutine assumes that the identifier
    # is related to the filename, but in the worst case we might have to
    # grep through all (not yet parsed) files to find the one.
    def lGetFilelistForIdentifier(self, sIdentifier, sType):
        if sType=="file":
            return [self.FindFile(sIdentifier)]
        
        # Look for possible Fortran files with 'similar' name
        l=[]
        for i in ["%s","%s.f","%s.F","%s.f90","%s.F90","%s.inc","%s.h",
                  "mod_%s.f","mod_%s.F","mod_%s.f90","mod_%s.F90"]:
            sFilename=i%sIdentifier
            if os.access(sFilename, os.R_OK):
                l.append(sFilename)
        if l: return l
        
        # Now try again with the filename in lower case
        sIdentifier=sIdentifier.lower()
        for i in ["%s","%s.f","%s.F","%s.f90","%s.F90","%s.inc","%s.h",
                  "mod_%s.f","mod_%s.F","mod_%s.f90","mod_%s.F90"]:
            sFilename=i%sIdentifier
            if os.access(sFilename, os.R_OK):
                l.append(sFilename)
        if l: return l
        # We should grep for the symbol in all files next
        return []
        
    # --------------------------------------------------------------------------
    def oGetObjectForIdentifier(self, sIdentifier, sType):
        obj=self.Cache.oGetFile(sIdentifier, sType)
        if obj:
            return obj
        for sFilename in self.lGetFilelistForIdentifier(sIdentifier, sType):
            if not self.dRecursiveTest.get(sFilename,None):
                self.dRecursiveTest[sFilename]=1
                objFile = Parser(sFilename=sFilename, project=self)
                # When a parsing error occurs, none is returned
                if objFile:
                    self.Cache.Store(objFile)
                del self.dRecursiveTest[sFilename]
                if sType=="file":
                    id = objFile
                else:
                    id = objFile.GetIdentifier(sIdentifier, sType)
                if id:
                    return id
        return None
            
    # --------------------------------------------------------------------------
    def dGetFileOptions(self, sFilename):
        d=self.dAddFileInfo.get(sFilename,{})
        return d class VarUsage:
    # If bUseUnknown is set to 0, all 'unknown' variables will be appended
    # to read and write instead of to 'unknown'. Depending on the application
    # that is more useful (e.g. call sub(a) --> a will be read/write instead
    # of unknown).
    def __init__(self, bUseUnknown=1):
        self.dRead       = {}
        self.dWrite      = {}
        self.dUnknown    = {}
        self.bUseUnknown = bUseUnknown;
        self.dType2Dict  = {"read"      : self.dRead,
                            "write"     : self.dWrite,
                            "unknown"   : self.dUnknown  }
        # Variables can be set to be ignored, for example:
        # loop variables might be ignored, so that they are
        # not reported as being read/written
        self.dIgnore     = {}
    # --------------------------------------------------------------------------
    def __str__(self): return self.__repr__()
    # --------------------------------------------------------------------------
    def __repr__(self):
        s=""
        for i in ("read", "write","unknown"):
            d = self.dType2Dict[i]
            if d:
                s="%s%s: %s\n"%(s, i, `d`)
        return s
    # --------------------------------------------------------------------------
    def addVariableToIgnore(self, s):
        if s.__class__ == Variable:
            self.dIgnore[`s`.lower()]=1
        else:  # assume string:
            self.dIgnore[s.lower()]=1
    # --------------------------------------------------------------------------
    def stopIgnoringVariable(self,s):
        if s.__class__ == Variable:
            del self.dIgnore[`s`.lower()]
        else:
            del self.dIgnore[s.lower()]
            
    # --------------------------------------------------------------------------
    # Create a one line output for unit tests
    def GetTestOutput(self):
        s=""
        for i in ("read", "write", "unknown"):
            l = self.dType2Dict[i].keys()
            l.sort()
            if l:
                s1 = reduce(lambda s,x: s+","+`x`[1:-1], l)
                s="%s%s: %s; "%(s, i, s1)
        return s[:-2]

    # --------------------------------------------------------------------------
    def __getitem__(self, sType): return self.GetVarUsage(sType)
    # --------------------------------------------------------------------------
    def GetVarUsage(self, sType, sVar=None):
        s = sType.lower()
        if sVar==None:
            return self.dType2Dict[s]
        return self.dType2Dict[s][sVar]
    # --------------------------------------------------------------------------
    def AddVariable(self, v, sType="read", obj=None, loc=None):
        # If no unknown state is to be saved, save all 'unknown' as read and as
        # write.
        if sType=="unknown" and not self.bUseUnknown:
            self.AddVariable(v, "read",  obj=obj, loc=loc)
            self.AddVariable(v, "write", obj=obj, loc=loc)
            return

        if v.__class__ == str: return  # e.g. a(:) --> the ":" appears as string
        if v.__class__ != Variable:
            v.GetVarUsage(self, sType, obj, loc)
            return

        # We have to use the name of the variable, since the same variable
        # (name) might have different variable objects representing it
        sVar=`v`.lower()
        
        # Check if the variable should be ignored
        if self.dIgnore.get(sVar,None): return
        
        if obj: loc = obj.GetLocation()
        l = self.dType2Dict[sType].get(sVar)
        if l:
            l.append(loc)
        else:
            self.dType2Dict[sType][sVar]=[loc]
        return

    # -------------------------------------------------------------------------- def Parser(sFilename=None, sInput=None, lInputLines=None,
           sFormat=None, project=None):
    p = ParserClass(sFilename=sFilename, sInput=sInput, sFormat=sFormat,
                    lInputLines=lInputLines, project=project)
    return p.GetFileObject() class f77(DefaultStylesheet):
    
    def __init__(self):
        DefaultStylesheet.__init__(self, 'fixed')
        self['keywordcase']    = 'identical'
        self['contlinemarker'] = '>'
    # -------------------------------------------------------------------------
    # This splits a list which represents a BasicStatement into a list of
    # list (of strings), the outer list each representing a new line, the inner
    # list of strings representing the actual statement. This functions
    # basically creates new lines dictated by the original progam layout by
    # inserting the comments, directives, ... from the AttributeStrings, and
    # if necessary split lines if they are too long for the maximum line length.
    def SplitIntoLines(self, l, bIgnoreAttributes=0):
        # The single line l (i.e. a list consisting of strings) is split into a
        # list of lines (each line again a list of strings). As a first step
        # any necessary line breaks in the original program (like comment line,
        # compiler directives, ...) are used to split each line.
        
        # The first element of l is the label (if exist) plus the spaces to
        # start at the (potential indentation marker) column, the second
        # element the correct number of spaces for indentation (see
        # BasicStatement). This is the prefix which has to be prepended to each
        # 'real' (not comment, directive, ...) statement. This second element
        # is always a real string (since this is constructed in BasicElement
        # based on the indentation function of the current stylesheet), but the
        # first element (either an empty string or a label string) might
        # contain attributes.
        lLines = []
        lCurr  = Layout2d()
        if type(l[0])==str or bIgnoreAttributes:
            lStartStatement = l[0:2]
        else:
            # The first element has attributes (i.e. there is a label and any
            # attributes before):
            for i in l[0].GetPrefixAttributes():
                lLines.append(`i`)
            lStartStatement=[" "*(self['startcolumn']-1), l[1]]
            
        lCurr.extend(l[0:2])

        # nCurrentColumn is the current column, startign with 0 for the first
        # column. It is used to indent comments in the same line as an
        # executable statement correctly.
        nCurrentColumn = len(l[0])+len(l[1])
        for i in l[2:]:
            if type(i)==str or bIgnoreAttributes:
                # Check if the current string fits into the current line.
                # Since this is a string (and not an AttributeString), it
                # is clear that this string is part of the statement, we don't
                # have to test if a comment would be after maxcols (which
                # wouldn't matter).
                # In case that it is a single string (e.g. a comment), and
                # it's the first thing, we don't break the line. This helps
                # in case of a comment that's longer than the line length.
                if nCurrentColumn+len(i)>self['maxcols'] and \
                       nCurrentColumn!=0:
                    lLines.append(lCurr)
                    lCurr = Layout2d()
                    lCurr.indent(self['startcolumn']-2)
                    lCurr.extend([self['contlinemarker'], i])
                    nCurrentColumn = self['startcolumn']-1+len(i)
                else:
                    lCurr.append(i)
                    nCurrentColumn = nCurrentColumn + len(i)
                continue
            # Now i is an Attribute string. First look for prefix attributes
            # Each of those must start on a new line, but a ContMarker is an
            # exception, since is is (for sure) the last attribute in a line,
            # AND it does not start a new line (in contrary it forces that
            # the next string belongs to the same line!!).
            s=i.GetString()
            
            # When the first prefix attribute is handled, there is some
            # data in lCurr, which needs to be appended. 
            bIsFirst = 1
            for j in i.GetPrefixAttributes():
                if j.__class__==ContMarker:
                    # Handling the special case: do not start a new line,
                    # instead append the next string, since it does belong
                    # to the same line!!
                    if bIsFirst:
                        lLines.append(lCurr)
                    lCurr= Layout2d()
                    lCurr.indent(self['startcolumn']-2)
                    lCurr.append(`j`)
                    lCurr.extend([lStartStatement[1],s])
                    nCurrentColumn = self['startcolumn']-1 +\
                                     len(lStartStatement[1])+len(s)
                    break
                else:
                    if bIsFirst:
                        lLines.append(lCurr)
                    bIsFirst = 0
                    lLines.append(`j`)
                    lCurr = Layout2d()
            else:
                # This is not executed if a ContMarker was added. This basically
                # means we have to start a new line, because of the attribute -
                # except if there was no prefix attribute (e.g .only a comment
                # at the end of a line) - in this case the string has to be
                # added to the current line.
                # Only if no ContMarker was added, we have to append the string
                # next. And, in this case, it always starts a new line!!!
                if len(i.GetPrefixAttributes())==0:
                    lCurr.append(s)
                    nCurrentColumn = nCurrentColumn+len(s)
                # The current line is empty, i.e. it only contained
                # the strings for indentation --> the line is overwritten
                # with the actual string to append
                elif len(lCurr.lElements)==2:
                    lCurr = Layout2d()
                    lCurr.extend(lStartStatement+[s])
                    nCurrentColumn = self['startcolumn']+1 + \
                                     len(lStartStatement[1])+len(s)
                # Start a new line for the actual string
                else:
                    lLines.append(lCurr)
                    lCurr = Layout2d()
                    lCurr.extend(lStartStatement+[s])
                    nCurrentColumn = self['startcolumn']+1 + \
                                     len(lStartStatement[1])+len(s)
                    
            lPostfix = i.GetPostfixAttributes()
            for j in lPostfix:
                if j.__class__==Comment:
                    lCurr.extend([' '*(j.GetLocation()[1]-nCurrentColumn-1),
                                       `j`])
                else:
                    lCurr.append([' %s'%`j`])  # Add at least one space here
        lLines.append(lCurr)
        return lLines
    # --------------------------------------------------------------------------
    def ToList(self, obj, l, bIgnoreAttributes=0):
        if not isinstance(obj, ProgUnit):
            return DefaultStylesheet.ToList(self, obj, l,
                                            bIgnoreAttributes=bIgnoreAttributes)
        
        l2d     = Layout2d()
        obj.ToList(self, l2d)
        for i in l2d:
            l.extend(self.SplitIntoLines( i.lToSimpleList(),
                                          bIgnoreAttributes ) )
        return class DefaultStylesheet(HasConfig):
    dCase2Function = {'upper'          : string.upper,
                      'lower'          : string.lower,
                      'identical'      : lambda x:x,
                      'capitalized'    : string.capitalize}


    # --------------------------------------------------------------------------
    def __init__(self, sFormat='fixed'):
        HasConfig.__init__(self)
        self.dMyConfig       = self.config['stylesheet'].copy()
        # The original structure is
        # Config['startcolumn']={'fixed': ..., 'free':...}
        # Since this is somewhat complicated to handle, the structure
        # for the stylesheets is changed so that the format is not
        # used anymore.
        self['startcolumn' ] = self['startcolumn'][self["format"]]
        self['maxcols'     ] = self['maxcols'    ][self["format"]]
        self['keywordcase' ] = "upper"
        self['variablecase'] = "lower"

    # -------------------------------------------------------------------------
    def get(self, sKey, default=None):
        return self.dMyConfig.get(sKey, default)
   # -------------------------------------------------------------------------
    def __getitem__(self, sKey):
        try:
            return self.dMyConfig[string.lower(sKey)]
        except KeyError:
            return None
    # -------------------------------------------------------------------------
    def __setitem__(self, sKey, value):
        sKey=sKey.lower()
        self.dMyConfig[sKey] = value
        if sKey=="keywordcase":
            self.dMyConfig['keywordcase' ] = self.dCase2Function.get(value,
                                                                     lambda x:x)
        elif sKey=="variablecase":
            self.dMyConfig['variablecase'] = self.dCase2Function.get(value,
                                                                     lambda x:x)
    # -------------------------------------------------------------------------
    # Creates the correct capitalisation for a keyword (i.e. upper case, lower
    # case, .... Parameters:
    #
    # s -- The keyword 
    def sKeyword(self, s): return self['keywordcase'](s)
    # -------------------------------------------------------------------------
    # Creates the correct capitalisation (or whatever) for a variable name
    def sVariable(self, s): return self['variablecase'](s)
    # -------------------------------------------------------------------------
    def GetIndentation(self, statement):
        return (" "*self['indent']) * (statement.GetIndentation()-1)
    # -------------------------------------------------------------------------
    # Returns the right amount of spaces, so that a character following
    # these spaces will be on the first column defined in this stylesheet.
    def sGetStartColumnSpaces(self):
        return ' '*(self['startcolumn']-1)
    # -------------------------------------------------------------------------
    # Converts an object to a list of strings (and lists). This basically calls
    # ToList in the object, but by overwriting this method different layout
    # functions can be used.
    def ToList(self, obj, l, bIgnoreAttributes=0):
        if type(obj)==StringType:
            l.append(obj)
        elif type(obj)==ListType:
            l.append(obj)
        else:
            obj.ToList(self, l)
    # -------------------------------------------------------------------------
    # Split a line into several lines if necessary. This needs to be
    # overwritten by the stylesheets.
    def SplitIntoLines(self, l, bIgnoreAttributes=0):
        return [l]
    # -------------------------------------------------------------------------
    # Takes the result of a ToList call and returns a string representation.
    def ToString(self, obj, bIgnoreAttributes=0):
        # *sigh* It's definitively not nice to import here, but otherwise
        # we have a circular reference:
        # BasicStatement -> Default -> File -> BasicStatement :((((
        from AOR.File           import File
        from AOR.ProgUnit       import ProgUnit
        from AOR.BasicStatement import BasicStatement
        from   Tools.functions  import flatten
        # We have to handle a few special cases:
        # 1) Displaying a progam unit: a program unit is a list of
        #    statements, i.e. a list of [list representing the statement]
        #    We have to convert each [list representing the statement] to a
        #    string, and then concatenate this list of strings with newlines
        # 2) Displaying a file: a file is a list of subroutines (which is a list
        #    of list of (strings and list), see above).
        if isinstance(obj, ProgUnit) or obj.__class__==File:
            l = MultiLine2d()
            self.ToList(obj, l, bIgnoreAttributes=bIgnoreAttributes)
            return `l`
        # 3) otherwise, we have (at most) a complete statement, so the
        #    list can be flattened and all strings then concatenated.
        elif isinstance(obj, BasicStatement):
            l = Layout2d()
            #l = MultiLine2d()
            self.ToList(obj, l, bIgnoreAttributes=bIgnoreAttributes)
            l1 = self.SplitIntoLines(l.lToSimpleList(), 
                                     bIgnoreAttributes=bIgnoreAttributes)
            l=[]
            for i in l1:
                l.append("".join(i))
            return "\n".join(l)
        else:
        # 4) Simple expressions etc., which all go on a single line, no newline
            l = Layout2d()
            self.ToList(obj, l, bIgnoreAttributes=bIgnoreAttributes)
            return `l`
    # ------------------------------------------------------------------------- class Declaration(BasicStatement):
    def __init__(self, sType, sComma=None, loc=None, nIndent=0, var=None,
                 attribute=None):
        BasicStatement.__init__(self, None, loc, nIndent)
        self.sType        = sType
        self.sComma       = sComma
        self.lAttributes  = DoubleList()
        self.lColons      = []
        self.lVars        = DoubleList()
        if var:
            self.AppendVariable(var)
        if attribute:
            self.AddAttribute(attribute)
    # --------------------------------------------------------------------------
    # Add a variable or an array specification to the list of declaration
    def AddDeclaredVariable(self, var, sComma=None):
        self.lVars.append(var, sComma)
    # --------------------------------------------------------------------------
    # Add an attribute, like 'allocateable', ...
    def AddAttribute(self, sAtt, sComma=None):
        if len(self.lAttributes)==0 and not self.sComma:
            self.sComma=","
        self.lAttributes.append(sAtt, sComma)
    # --------------------------------------------------------------------------
    # Adds the optional double colon of a declaration. Parameters:
    # 
    # c1/c2 -- Each of the two colons (the scanner returns two colons for a ::)
    def AddDoubleColons(self, c1, c2): self.lColons=[c1,c2]
    # --------------------------------------------------------------------------
    # This function is used to construct new declaration statements:
    def AppendVariable(self, v):
        if len(self.lVars)==0:
            self.lColons=[":",":"]
            self.lVars.append(v)
        else:
            self.lVars.append(",", v)
    # --------------------------------------------------------------------------
    def GetAttributes(self):
        return self.lAttributes.GetMainList()
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        stylesheet.ToList(self.sType, l)
        if self.sComma:
            l.append(self.sComma)
        l.indent(1)
        # The if is not really necessary, but without it two spaces
        # would be added in case of an empy attribute list
        if len(self.lAttributes.GetMainList())>0:
            self.lAttributes.ToList(stylesheet, l, bAddSpace=1)
            l.indent(1)
        if self.lColons:
            l.extend(self.lColons)
            l.indent(1)
        self.lVars.ToList(stylesheet, l, bAddSpace=1) class VariableWithInit(BasicRepr):
    def __init__(self, var, sEqual=None, value=None, dataobj=None):
        self.var = var
        if sEqual:
            self.value  = value
            self.sEqual = sEqual
        else:
            self.value  = dataobj
            self.sEqual = None
    # --------------------------------------------------------------------------
    def GetAllUsedVariables(self):
        return self.var.GetAllUsedVariables()
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        if self.sEqual:
            self.var.ToList(stylesheet, l)
            l.append(self.sEqual)
            self.value.ToList(stylesheet, l)
        else:
            self.var.ToList(stylesheet, l)
            l.indent(1)
            self.value.ToList(stylesheet, l) class Include(BasicStatement):
    def __init__(self, loc=None, sInclude="include", sFilename=None, nIndent=0):
        BasicStatement.__init__(self, None, loc, nIndent)
        self.sInclude  = sInclude
        self.sFilename = sFilename
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        l.append(self.sInclude)
        l.append(self.sFilename, nIndent=1) class Expression(BasicExpression):
    def __init__(self, o=None, operator=None, o2=None):
        BasicExpression.__init__(self, o=o, operator=operator, o2=o2) class Literal(BasicRepr):
    # Stores a literal, i.e. a number (which is stored as a string here so that
    # the number can be stored without rounding problems and in the way it was
    # specified by the user). This class is only necessary to avoid
    # distinguishing different cases in each __repr__ call, since a string like
    # "2.0" would be returned as '2.0' by ``, so "2.0*f" would be returned as
    # "'2.0'*f". (without these class we would have to test in many classes if
    # the object is a string, and if so not use `` but the plain string).
    # Parameters:
    #
    # sLiteral -- The Literal
    #
    def __init__(self, sLiteral):
        self.sLit = sLiteral
    # --------------------------------------------------------------------------
    def GetAllUsedVariables(self):
        return []
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage, sType="read", obj=None, loc=None): return
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l): l.append(self.sLit)
    # --------------------------------------------------------------------------
    def __repr__(self):
        return self.sLit class ArraySpecWithName(BasicRepr):
    def __init__(self, var=None, sName="", arrayspec=None, sParOpen=None):
        self.var           = var
        self.sName         = sName
        if not arrayspec:
            self.arrayspec = ArraySpec()
        else:
            self.arrayspec = arrayspec
        if sParOpen:
            self.arrayspec.SetParOpen(sParOpen)
        else:
            self.arrayspec.SetParOpen("(")
    # --------------------------------------------------------------------------
    def SetAttribute(self, att, value): self.var.SetAttribute(att, value)
    # --------------------------------------------------------------------------
    def SetParOpen(self, sParOpen):
        self.arrayspec.SetParOpen(sParOpen)
    # --------------------------------------------------------------------------
    def SetParClose(self, sParClose):
        self.arrayspec.SetParClose(sParClose)
    # --------------------------------------------------------------------------
    def AddSubscript(self, exp, sComma=None):
        self.arrayspec.AddSubscript(exp, sComma)
    # --------------------------------------------------------------------------
    def GetArraySpec(self): return self.arrayspec
    # --------------------------------------------------------------------------
    def oGetVariable(self): return self.var
    # --------------------------------------------------------------------------
    # Returns a list of all variables used in this array declaration
    def GetAllUsedVariables(self):
        return self.arrayspec.GetAllUsedVariables()
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage, sType="read", obj=None, loc=None):
        # Add the main variable as whatever is appropriate (read or write).
        # e.g: a(i) = b(i) --> a will have sType='write', and b will have
        # sType="read"
        if self.var:
            varUsage.AddVariable(self.var,   sType,  obj, loc)
        varUsage.AddVariable(self.arrayspec, "read", obj, loc)
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        if self.var:
            stylesheet.ToList(self.var, l)
        elif self.sName:
            l.append(stylesheet.sKeyword(self.sName))
        self.arrayspec.ToList(stylesheet, l) class TrueFalse(Literal):
    # Stores a .true. or .false. statement. This is basically a Literal class,
    # except that this is a keyword (so must be handled differently when
    # using stylesheets). Parameters:
    #
    # sLiteral -- The Literal
    #
    def __init__(self, sLiteral):
        Literal.__init__(self, sLiteral)
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        l.append(stylesheet.sKeyword('%s'%self)) class VariableData(UserDict):

    # Stores information about a variable. This object is a dictionary itself,
    # so the attributes of a variable can be accessed via [] etc. Only one
    # instance of this object is created, each Variable instance contains a
    # pointer to this object which is used to store and retrieve information/
    # Parameter:
    #
    # sName -- Name of the variable
    #
    # dType -- Type information of the variable
    #          'argument'   : 1 if the variable is an argument
    #          'dimension'  : for arrays only: contains ArraySpec
    #          'type'       : type of the variable (class Type)
    #          'undefined'  : 1 if not defined (type will then be implicit)
    #          'allocatable': 1 if allocatable
    #          'pointer'    : 1 if pointer
    #          'target'     : 1 if target
    #          'parameter'  : 1 if parameter
    #          'optional'   : 1 if optional
    #          'save'       : 1 if save
    #          'intent'     : a Intent instance
    #          'kind'       : kind information
    #          'module'     : module-name: for variables from a module
    #          'renamedfrom': orig name. Variable renamed from a module
    #          'common'     : variable belongs to a common block, value is
    #                         the common block statement
    #          'include'    : true if this variable was declared in an
    #                         included file, object is the include file name
    #          'equivalence': variable is used in an equivalence statement
    #                         value is a list of equivalence items in which
    #                         the variable is used.
    #          'init'       : An initial value, e.g. integer, parameter:n=3
    
    def __init__(self, sName, dType=None):
        if not dType: dType={}
        UserDict.__init__(self, dType)
        self.sName = sName
    # --------------------------------------------------------------------------
    # Overwrite the default, so that no excpetion is raised for
    # non existing attributes
    def __getitem__(self, key):
        return self.data.get(key, None)
    # --------------------------------------------------------------------------
    # Returns the current name of the variable (the current name is either the
    # original one or a renamed one.
    def sGetName(self): return self.sName
    # --------------------------------------------------------------------------
    def SetName(self, s) : self.sName=s
    # --------------------------------------------------------------------------
    def bIsArray(self):
        return self['dimension'] or self['type'].bIsType("CHARACTER")
    # --------------------------------------------------------------------------
    # This creates a declaration statment which declares the current variable.
    # The result is a real AOR object, not just a list
    def oCreateDeclarationStatement(self, nIndent, bUseInclude=1, bUseModule=1,
                                    sNewName="", bAddInit=0):
        if self['include'] and bUseInclude:
            return PreDirective('#include "%s"'%self['include'],(0,0))
        if self['module'] and bUseModule:
            use = Use('USE', nIndent=nIndent)
            use.SetName(self['module'])
            use.AddComma(',')
            if self['renamedfrom']:
                if sNewName:
                    use.AddRename(self['renamedfrom'],'=>', sNewName)
                else:
                    use.AddRename(self['renamedfrom'],'=>', self.sName)
            else:
                use.AddOnlyString('ONLY',':')
                use.AddOnly(self)
            return use
        l=[]
        # First handle all attributes which are basically strings:
        for i in ['allocatable','pointer','target','parameter','optional',
                  'save','kind']:
            if self[i]:
                l.extend([i,','])
        # Now handle dimension statements (the value of the dimension
        # attribute is actually an ArraySpec, so we have to create a
        # new ArraySpecWithName object here).
        if self['dimension']:
            l.extend([ArraySpecWithName(sName='dimension',
                                        arrayspec=self['dimension']), ','])
        # The value of 'intent' is actually an object, which can be used
        # directly here.
        if self['intent']:
            l.extend([self['intent'], ', '])
        # Remove the last comma and create the Declaration object:
        if l and l[-1]==',':
            del l[-1]
            decl = Declaration(self['type'], sComma=',', nIndent=nIndent)
        else:
            decl = Declaration(self['type'], nIndent=nIndent)

        # Now add all attributes and the commas
        for i in range(0, len(l)-1, 2):
            decl.AddAttribute(l[i],l[i+1])
        if l: decl.AddAttribute(l[-1])
        decl.AddDoubleColons(':',':')
        if bAddInit and self["init"]:
            decl.AppendVariable(VariableWithInit(self,"=",self["init"]))
        else:
            if sNewName:
                decl.AppendVariable(Variable(sNewName, self))
            else:
                decl.AppendVariable(Variable(self.sName, self))

        return decl
        
    # --------------------------------------------------------------------------
    # This is basically a ToList method for creating proper declaration of a
    # variable, e.g. for interfaces, .... The returned list will have the usual
    # 'special' first two elements: the first one a label plus potential
    # indentation (to start the correct start column), the second one
    # correct indentation for the logical nesting (which is in this case a '').
    def lGetDeclaration(self, stylesheet):
        # First, test if the variable was declared in a module. If so,
        # create the proper use statement:
        if self['module']:
            if self['renamedfrom']:
                return [stylesheet.sGetStartColumnSpaces(), '',
                        stylesheet.sKeyword('USE'),' ',
                        self['module'],', ',self['renamedfrom'],'=>',
                        self.sName]
            else:
                return [stylesheet.sGetStartColumnSpaces(),'',
                        stylesheet.sKeyword('USE'),' ',self['module'],
                        ', ',stylesheet.sKeyword('ONLY'),':', self.sName]
        # Each variable has a type, since the default type will be set!
        l=[stylesheet.sGetStartColumnSpaces(),'',"%s"%self['type'], ', ' ]
        for i in ['allocatable','pointer','target','parameter','optional',
                  'save']:
            if self[i]: l.extend([i, ', '])
        if self['kind']: l.extend([self['kind'], ', '])
        if self['dimension']:
            l.extend(["DIMENSION%s"%self.GetDimensionAsString(), ', '])
        if self['intent']: l.extend(["INTENT(%s)"%self['intent'], ', '])
        # The last element of the list is a ', ', so this must be removed!
        l[-1]=' :: '
        l.append(self.sName)
        return l
    # --------------------------------------------------------------------------
    def GetDeclarationAsString(self, stylesheet):
        return "".join(self.lGetDeclaration(stylesheet))
    # --------------------------------------------------------------------------
    # Returns a list of all variables used when declaring this variable.
    # The variable itself is added to the list of variables in the Variable
    # objects. This is necessary::
    # consider the example expressions 'a' and 'a+b'. GetAllUsedVaraibles for
    # the latter one has to return 'a' and 'b' as part of the sum expression,
    # so the first expression has to return 'a'. But since this expression is
    # only a variable, each variable has to return itself as a used variable.
    def GetAllUsedVariables(self):
        l = []
        if self['include'  ]:
            return l
        if self['dimension']: l.extend(self['dimension'].GetAllUsedVariables())
        if self['common'   ]: l.append(self['common'   ])
        if self['init'     ]: l.extend(self['init'].GetAllUsedVariables())
        return l
    # --------------------------------------------------------------------------
    # Sets an attributes for the variable. The attribute can be either
    # a string (in which case the value is set to 1), or an object
    # (e.g. dimension, type).
    def SetAttribute(self, att, value=1):
        if att=='equivalence':
            if self[att]:
                self[att].append(value)
            else:
                self[att]=[value]
        else:
            self[att]=value
    # --------------------------------------------------------------------------
    # Returns a dictionary with all attributes of a variable.
    def GetAttributes(self): return self
    # --------------------------------------------------------------------------
    # Returns a string with the correct declaration of the variable, e.g.
    # '(1:2, 3:, nlat_dyn+3, nlon_dyn,*)'
    def GetDimensionAsString(self):
        dim=self.get('dimension',None)
        if not dim: return ""
        return `dim`
        
    # --------------------------------------------------------------------------
    # Displays the variable name and all attributes
    def DisplayAll(self):
        return '%s[%s]'%(self.sName, UserDict.__repr__(self))
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l): l.append(stylesheet.sVariable(self.sName))
    # --------------------------------------------------------------------------
    # Returns just the variable name.
    def __repr__(self):
        return self.sName.__str__() class Variable:
    def __init__(self, sName, oVariableData=None):
        self.sName    = sName                     # Potential an AttributeString
        if oVariableData:
            self.oVarData = oVariableData
        else:
            self.oVarData = VariableData(self.sName,{})
    # --------------------------------------------------------------------------
    # Forward this to the actual VariableData instance
    def __getitem__(self, key): return self.oVarData[key]
    # --------------------------------------------------------------------------
    # Forward this to the actual VariableData instance
    def __setitem__(self, key, value):
        return self.oVarData.__setitem__(key, value)
    # --------------------------------------------------------------------------
    # Forward this to the actual VariableData instance
    def __delitem__(self, key):
        return self.oVarData.__delitem__(key)
    # --------------------------------------------------------------------------
    # This is necessary, since for example in a common block an expression
    # like common /xx/ a, b(10) can be used. Now, to store the information
    # that a common block is used, we need acces to the variable b (which is
    # an ArrayRef). To avoid further tests, the same method is implemented
    # for variables as well.
    def oGetVariable(self): return self
    # --------------------------------------------------------------------------
    # Forward this to the actual VariableData instance
    def GetDeclarationAsString(self, stylesheet):
        return self.oVarData.GetDeclarationAsString(stylesheet)
    # --------------------------------------------------------------------------
    def GetAllUsedVariables(self):
        l = self.oVarData.GetAllUsedVariables()
        l.append(self)
        return l
    # --------------------------------------------------------------------------
    # Sets an attributes for the variable. The attribute can be either
    # a string (in which case the value is set to 1), or an object
    # (e.g. dimension, type). This is forwarded to the respective VariableData
    # instance.
    def SetAttribute(self, att, value=1):
        return self.oVarData.SetAttribute(att, value)
    # --------------------------------------------------------------------------
    # Returns a dictionary with all attributes of a variable.
    def GetAttributes(self): return self.oVarData.GetAttributes()
    # --------------------------------------------------------------------------
    def sGetName(self): return self.oVarData.sGetName()
    # --------------------------------------------------------------------------
    def SetName(self, s) : self.oVarData.SetName(s)
    # --------------------------------------------------------------------------
    # Returns a string with the correct declaration of the variable, e.g.
    # '(1:2, 3:, nlat_dyn+3, nlon_dyn,*)'. This is forwarded to the respective
    # VariableData instance.
    def GetDimensionAsString(self): return self.oVarData.GetDimensionAsString()
    # --------------------------------------------------------------------------
    def oCreateDeclarationStatement(self, nIndent=0, bUseInclude=1, bUseModule=1,
                                    sNewName="", bAddInit=0):
        return self.oVarData.oCreateDeclarationStatement(nIndent,
                                                         bUseInclude=bUseInclude,
                                                         bUseModule=bUseModule,
                                                         sNewName=sNewName,
                                                         bAddInit=bAddInit)
    # --------------------------------------------------------------------------
    def bTypeIs(self, sType):
        return self["type"].bIsType(sType)
    # --------------------------------------------------------------------------
    def bIsArray(self): return self.oVarData.bIsArray()
    # --------------------------------------------------------------------------
    # Displays the variable name and all attributes. This is forwarded to the
    # respective VariableData instance.
    def DisplayAll(self): return self.oVarData.DisplayAll()
    # --------------------------------------------------------------------------
    # Needed for layout2d
    def __len__(self): return len(self.sName)
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        sCurrentName = self.oVarData.sGetName()
        if string.lower(sCurrentName)==string.lower(self.sName):
            l.append(stylesheet.sVariable(self.sName))
            return
        # The variable has been renamed. If the current name is a normal string,
        # simply replace it with the new name:
        if type(self.sName)==type(''):
            self.sName=sCurrentName
            l.append(sCurrentName)
            return
        # Otherwise sName is an AttributeString. Create a new instance of
        # AttributeString
        self.sName = self.sName.sCreateCopy(sCurrentName)
        l.append(stylesheet.sVariable(self.sName))
    # --------------------------------------------------------------------------
    def __repr__(self): return self.sName
    # -------------------------------------------------------------------------- class Allocate(BasicStatement):

    # Stores a return statement.
    def __init__(self, sLabel=None, loc=None, sOp='ALLOCATE',sParOpen='(',
                 nIndent=0):
        BasicStatement.__init__(self, sLabel, loc, nIndent, isDeclaration=0)
        self.sOp             = sOp
        self.sParOpen        = sParOpen
        self.lVars           = DoubleList()
        self.lOptions        = DoubleList()
        self.sParClose       = ")"
    # --------------------------------------------------------------------------
    def SetParClose(self, sParClose): self.sParClose = sParClose
    # --------------------------------------------------------------------------
    # Adds a variable to allocate to the allocate statement. Parameters:
    #
    # var -- Variable to add
    #
    # sSeparator -- String which separates a variable from the next. Usual a
    #               comma, but the ')' is stored here as well.
    def AddVariable(self, var, sSeparator=None):
        self.lVars.append(var, sSeparator)
    # --------------------------------------------------------------------------
    # Appends an option (stat, errmsg, or source) to the statement. Parameters:
    #
    # sName -- Name of the option
    #
    # sEqual -- The '=' character
    #
    # obj -- A scalar int variable
    #
    # sSeparator -- String which separates an option from the next. Usual a
    #               comma, but the ')' can be stored here as well.
    def AddOption(self, sName, sEqual, obj, sSeparator=None):
        self.lOptions.append( OptionString(sName, sEqual, obj), sSeparator )
    # --------------------------------------------------------------------------
    # Creates a list of strings which represents this statement. Parameters:
    #
    # stylesheet -- The stylesheet to use during layout
    def ToList(self, stylesheet=None,l=[]):
        BasicStatement.ToList(self, stylesheet, l)
        l.extend([stylesheet.sKeyword(self.sOp), self.sParOpen]) # 'allocate', '('
        self.lVars.ToList(stylesheet, l)
        self.lOptions.ToList(stylesheet, l)
        l.append(self.sParClose) class Call(FunctionCall, BasicStatement):
    def __init__(self, sLabel=None, loc=None, sCall="CALL", sName=None,
                 nIndent=0):
        BasicStatement.__init__(self, sLabel, loc, nIndent, isDeclaration=0)
        FunctionCall.__init__(self, sName)
        self.sCall = sCall
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        l.append(stylesheet.sKeyword(self.sCall), nIndentNext=1)
        FunctionCall.ToList(self, stylesheet, l) class Assignment(BasicStatement):

    # Stores an assignment or pointer assignment statement:
    # assignment-stmt is variable = expr   or
    # pointer-assignment-stmt is
    #     data-pointer-object [ (bounds-spec-list) ] => data-target or
    #     data-pointer-object (bounds-remapping-list ) => data-target or
    #     proc-pointer-object => proc-target
    # This object is not only used as a real statement e.g. it is used
    # in the Parameter object as well). If the flag bNoIndent is set
    # the object will not add indentation in ToList!!
    def __init__(self, sLabel=None, loc=None, nIndent=0, lhs=None,
                 sEqual='=', rhs=None, bNoIndent=None):
        BasicStatement.__init__(self, sLabel, loc, nIndent, isDeclaration=0)
        self.lhs       = lhs
        self.sEqual    = sEqual
        self.rhs       = rhs
        self.bNoIndent = bNoIndent
    # --------------------------------------------------------------------------
    # Define the left hand side of an assignment
    def SetLeftHandSide (self, ls): self.lhs=ls
    # --------------------------------------------------------------------------
    def SetRightHandSide(self, rs): self.rhs=rs
    # --------------------------------------------------------------------------
    def SetEqualSign(self, eq): self.eq = eq
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage, sType="read", obj=None, loc=None):
        varUsage.AddVariable(self.rhs, "read",  obj=self)
        varUsage.AddVariable(self.lhs, "write", obj=self)
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet,l):
        if not self.bNoIndent:
            BasicStatement.ToList(self, stylesheet, l)
        stylesheet.ToList(self.lhs, l)
        # one space before and after the =
        l.append(self.sEqual, nIndent=1, nIndentNext=1)
        stylesheet.ToList(self.rhs, l) class Stop(BasicStatement):
      # Stores a stop statement.
    def __init__(self, sLabel=None, loc=None, sStop="STOP", nIndent=0):
        BasicStatement.__init__(self, sLabel, loc, nIndent, isDeclaration=0)
        self.sStop    = sStop
        self.stopcode = None
    # --------------------------------------------------------------------------
    def SetStopCode(self, obj):
        self.stopcode = obj
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        if self.stopcode:
            l.append(stylesheet.sKeyword(self.sStop), nIndentNext=1)
            stylesheet.ToList(self.stopcode, l)
        else:
            l.append(stylesheet.sKeyword(self.sStop)) class FunctionCall(BasicRepr):

    # Stores a function call.
    def __init__(self, sName=None, sArg=None):
        self.sName     = sName
        self.lArgs     = DoubleList()
        self.sParOpen  = None
        self.sParClose = None
        if sArg:
            self.sParOpen="("
            self.AddArgument(sArg)
            self.sParClose=")"
    # --------------------------------------------------------------------------
    # Returns the name of the called subroutine
    def sGetName(self): return self.sName
    # --------------------------------------------------------------------------
    def lGetArgs(self): return self.lArgs
    # --------------------------------------------------------------------------
    def SetParOpen(self, sParOpen): self.sParOpen = sParOpen
    # --------------------------------------------------------------------------
    def SetParClose(self, sParClose): self.sParClose = sParClose
    # --------------------------------------------------------------------------
    # Adds an actual argument.
    def AddArgument(self, arg, sComma=None):
        if self.sParOpen==None: self.sParOpen="("
        self.sParClose = ")"
        if sComma==None and \
               len(self.lArgs.lGetSecondaryList())==len(self.lArgs)-1:
            self.lArgs.append(",", arg)
        else:
            self.lArgs.append(arg, sComma)
    # --------------------------------------------------------------------------
    # Adds a keyword argument: keyword=val
    def AddKeywordArgument(self, sKeyword, sEqual, obj, sComma=None):
        self.lArgs.append(OptionString(sKeyword, sEqual, obj), sComma)
    # --------------------------------------------------------------------------
    # Adds an alternate return specification: *123
    def AddAltReturn(self, sStar, sLabel, sComma=None):
        self.lArgs.append(StarLabel(sStar, sLabel), sComma)
    # --------------------------------------------------------------------------
    # Adds an alternate return specification with keyword: keyw=*123
    def AddKeywordAltReturn(self, sKeyword, sEqual, sStar, sLabel, sComma=None):
        self.lArgs.append(OptionString(sKeyword, sEqual,
                                       StarLabel(sStar, sLabel)), sComma)
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage, sType="read", obj=None, loc=None):
        for i in self.lArgs.GetMainList():
            varUsage.AddVariable(i, "unknown", obj, loc)
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        if stylesheet["mathsmode"]:
            s = string.lower(self.sName)
            if s=="sqrt" and stylesheet["dosqrt"]:
                return stylesheet.HandleSqrt(self, l)
            if s=="exp" and stylesheet["doexp"]:
                return stylesheet.HandleExp(self, l)
            if s=="abs" and stylesheet["doabs"]:
                return stylesheet.HandleAbs(self, l)
        l.append(self.sName)
        if not self.sParOpen: return
        l.append(self.sParOpen)
        self.lArgs.ToList(stylesheet, l, bAddSpace=1)
        l.append(self.sParClose) class Return(BasicStatement):

    # Stores a return statement.
    def __init__(self, sLabel=None, loc=None, sReturn="RETURN", nIndent=0):
        BasicStatement.__init__(self, sLabel, loc, nIndent, isDeclaration=0)
        self.sReturn  = sReturn
        self.retvalue = None
    # --------------------------------------------------------------------------
    def SetReturnValue(self, obj):
        self.retvalue = obj
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage):
        if self.retvalue:
            selt.retvalue.GetVarUsage(varUsage)
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        if self.retvalue:
            l.append(stylesheet.sKeyword(self.sReturn), nIndentNext=1)
            stylesheet.ToList(self.retvalue, l)
        else:
            l.append(stylesheet.sKeyword(self.sReturn)) class ControlLessDo(BasicNamedStatement):
    # Stores a Do loop without loop control
    def __init__(self, sLabel=None, sName=None, loc=None,
                 sDo="DO", sDoLabel=None, nIndent=0):
        self.sDo       = sDo
        self.sDoLabel  = sDoLabel
        self.lLoopData = []
        BasicNamedStatement.__init__(self, sLabel, sName, loc, nIndent,
                                     isDeclaration=0)
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage): return
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicNamedStatement.ToList(self, stylesheet, l)
        l.append(stylesheet.sKeyword(self.sDo))
        if self.sDoLabel:
            l.append(self.sDoLabel, nIndent=1) class Exit(BasicStatement):
    def __init__(self, sLabel=None, loc=None, sExit="EXIT", sExitLabel=None,
                 nIndent=0):
        BasicStatement.__init__(self, sLabel, loc, nIndent, isDeclaration=0)
        self.sExit      = sExit
        self.sExitLabel = sExitLabel
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage): return
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        if self.sExitLabel:
            BasicStatement.ToList(self, stylesheet, l)
            l.append(stylesheet.sKeyword(self.sExit), nIndentNext=1)
            l.append(self.sExitLabel)
        else:
            BasicStatement.ToList(self, stylesheet, l)
            l.append(stylesheet.sKeyword(self.sExit)) class EndDo(BasicStatement):

    # Stores an EndDo statement which can have a do-construct name
    #
    # sLabel -- Label of the statement (5 digit number as a string)
    #
    def __init__(self, sLabel=None, loc=None, sEnd='END', sDo='DO',  nIndent=0):
        self.lEndDo  = [sEnd, sDo]
        self.sName = None
        BasicStatement.__init__(self, sLabel, loc, nIndent, isDeclaration=0)
    # --------------------------------------------------------------------------
    def SetName(self, sName): self.sName = sName
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage): return
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        l.append(stylesheet.sKeyword(self.lEndDo[0]), nIndentNext=1)
        l.append(stylesheet.sKeyword(self.lEndDo[1]))
        if self.sName:
            l.append(self.sName) class Do(BasicNamedStatement):

    # Stores a Do-loop statement
    #
    # sLabel -- Label of the Do statement (this is NOT the label
    #           used in the DO loop, e.g.: 100 DO 200 i=1, 10
    #           This is the label 100, not the label 200
    #
    # sName -- Name of the do statement
    #
    def __init__(self, sLabel=None, sName=None, loc=None,
                 sDo="DO", sDoLabel=None, sOptComma=None, nIndent=0,
                 var=None, sFrom=None, sTo=None):
        self.sDo       = sDo
        self.sOptComma = sOptComma
        self.lLoopData = []
        self.sDoLabel  = sDoLabel
        BasicNamedStatement.__init__(self, sLabel, sName, loc, nIndent,
                                     isDeclaration=0)
        if var: self.SetVariable(var,"=")
        if sFrom: self.SetFrom(sFrom,",")
        if sTo: self.SetTo(sTo)
    # --------------------------------------------------------------------------
    def SetVariable(self, var, sEqual): self.lLoopData.extend([var, sEqual])
    # --------------------------------------------------------------------------
    def SetFrom(self, f, sComma): self.lLoopData.extend([f, sComma])
    # --------------------------------------------------------------------------
    def SetTo  (self, t): self.lLoopData.append(t)
    # --------------------------------------------------------------------------
    def SetStep(self, sComma, s): self.lLoopData.extend([sComma, s])
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage):
        varUsage.AddVariable(self.lLoopData[0], "write",self)   # the do variable is written
        varUsage.AddVariable(self.lLoopData[2], "read", self)
        varUsage.AddVariable(self.lLoopData[4], "read", self)
        if len(self.lLoopData)>5:
            varUsage.AddVariable (self.lLoopData[6], "read", self)
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicNamedStatement.ToList(self, stylesheet, l)
        l.append(stylesheet.sKeyword(self.sDo), nIndentNext=1)
        if self.sDoLabel:
            l.append(self.sDoLabel, nIndentNext=1)
        if self.sOptComma: l.append(self.sOptComma)
        stylesheet.ToList(self.lLoopData[0], l)               # var
        l.indent(1)
        l.append(self.lLoopData[1], nIndentNext=1)            # =
        stylesheet.ToList(self.lLoopData[2], l)               # from
        l.append(self.lLoopData[3], nIndentNext=1)            # ,
        stylesheet.ToList(self.lLoopData[4], l)               # to
        if len(self.lLoopData)>5:
            l.append(self.lLoopData[5],nIndentNext=1)         # ,
            stylesheet.ToList(self.lLoopData[6], l)           # step class IfOnly(BasicStatement):
    def __init__(self, sLabel=None, loc=None, sIf="IF", sParOpen='(',
                 oIfCond=None, sParClose=')', oStatement=None, nIndent=0):
        BasicStatement.__init__(self, sLabel, loc, nIndent, isDeclaration=0)
        self.sIf        = sIf
        self.l          = [sIf, sParOpen, oIfCond, sParClose, oStatement]
    # --------------------------------------------------------------------------
    # Returns the object representing the condition of an if-then statement
    def GetCondition(self): return self.l[2]
    # --------------------------------------------------------------------------
    # Returns the statement which is part of the if (without then) statement
    def GetStatement(self): return self.l[4]
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage):
        varUsage.AddVariable(self.l[2], "read", self)
        self.l[4].GetVarUsage(varUsage)
        
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        l.append(stylesheet.sKeyword(self.l[0]),nIndentNext=1)
        l.append(self.l[1])
        stylesheet.ToList(self.l[2], l)
        l.append(self.l[3],nIndentNext=1)
        stylesheet.ToList(self.l[4], l) class If(BasicNamedStatement):
    def __init__(self, sLabel=None, sName=None, loc=None, sIf="IF", nIndent=0,
                 sParOpen='(', oIfCond=None, sParClose=')', sThen='THEN'):
        BasicNamedStatement.__init__(self, sLabel, sName, loc, nIndent,
                                     isDeclaration=0)
        self.l = [sIf, sParOpen,  oIfCond, sParClose, sThen]
    # --------------------------------------------------------------------------
    # Returns the object representing the condition of an if-then statement
    def GetCondition(self): return self.l[2]
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage):
        varUsage.AddVariable(self.l[2], "read", self)
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicNamedStatement.ToList(self, stylesheet, l, bAddSpace=1)
        l.append(stylesheet.sKeyword(self.l[0]), nIndentNext=1)
        l.append(self.l[1])
        stylesheet.ToList(self.l[2], l)
        l.append(self.l[3], nIndentNext=1)
        l.append(stylesheet.sKeyword(self.l[4])) class EndIf(BasicStatement):
    def __init__(self, sLabel=None, loc=None, sEnd="END", sIf="IF", nIndent=0):
        BasicStatement.__init__(self, sLabel, loc,nIndent, isDeclaration=0)
        self.lEndIf = [sEnd, sIf]
        self.sName  = None
    # --------------------------------------------------------------------------
    def SetName(self, sName): self.sName = sName
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage): return
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        l.append(self.lEndIf[0]           )
        l.append(self.lEndIf[1], nIndent=1)
        if self.sName: l.append(self.sName, nIndent=1) class Write(Read):
    # Stores a write statement. Read and writes are basically identical,
    # except that read can have a format instead of a () expression
    def __init__(self, sLabel=None, loc=None, nIndent=0,
                 sWrite="WRITE", sParOpen=None, nUnit=None):
        Read.__init__(self, sLabel, loc, nIndent,
                      sRead=sWrite, sParOpen=sParOpen, nUnit=nUnit)
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage, sType="read", obj=None, loc=None):
        for i in self.lIOExp.GetMainList():
            varUsage.AddVariable(i, "read", obj, loc)
        BasicIOList.GetVarUsage(self, varUsage, sType, obj, loc) class Read(BasicIOList):
    # Stores a read statement
    def __init__(self, sLabel=None, loc=None, nIndent=0,
                 sRead="READ", sParOpen=None,
                 nUnit=None, var=None):
        BasicIOList.__init__(self, sLabel, loc, nIndent, sRead, sParOpen)
        self.lIOExp    = DoubleList()
        self.sFormat   = None
        self.sComma    = None
        if nUnit:
            if not sParOpen: self.SetParOpen()
            self.AddIOOpt("%s"%nUnit)
            self.SetParClose()
        if var:
            self.AddIOExpression(var)
    # --------------------------------------------------------------------------
    def SetFormat(self, sFormat, sComma=None):
        self.sFormat = sFormat
        self.sComma  = sComma
    # --------------------------------------------------------------------------
    def AddIOExpression(self, exp, sComma=None):
        # To simplify manually creating statements, a comma is automatically
        # added, if only expressions are specified here (except for the first
        # call).
        if type(exp)==type(1): exp=`exp`
        if sComma==None and \
               len(self.lIOExp.lGetSecondaryList())==len(self.lIOExp)-1:
            self.lIOExp.append(",", exp)
        else:
            self.lIOExp.append(exp, sComma)
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage, sType="read", obj=None, loc=None):
        for i in self.lIOExp.GetMainList():
            varUsage.AddVariable(i, "write", obj, loc)
        BasicIOList.GetVarUsage(self, varUsage, sType, obj, loc)
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicIOList.ToList(self, stylesheet, l)
        l.append(' ')
        if self.sFormat:
            l.append(self.sFormat, nIndent=1)
            if self.sComma:
                l.append(self.sComma)
        self.lIOExp.ToList(stylesheet, l) class Open(BasicIOList):
    # Stores an open statement
    def __init__(self, sLabel=None, loc=None, nIndent=0, sOpen="OPEN",
                 sParOpen='(', nUnit=None):
        BasicIOList.__init__(self, sLabel, loc, nIndent, sOpen, sParOpen,
                             opt=nUnit) class Print(BasicStatement):

    # Stores a return statement.
    def __init__(self, sLabel=None, loc=None, sPrint="PRINT", nIndent=0,
                 format=None):
        BasicStatement.__init__(self, sLabel, loc, nIndent, isDeclaration=0)
        self.sPrint  = sPrint
        self.format  = format
        if format:
            self.sComma  = ","              # First comma after format
        else:
            self.sComma  = None             # First comma after format
        self.lIO     = DoubleList()
    # --------------------------------------------------------------------------
    def AddIOExpression(self, e, sComma=None): self.lIO.append(e, sComma)
    # --------------------------------------------------------------------------
    def SetComma(self, sComma): self.sComma=sComma
    # --------------------------------------------------------------------------
    def GetVarUsage(self, varUsage, sType="read", obj=None, loc=None):
        for i in self.lIO.GetMainList():
            varUsage.AddVariable(i, sType, obj, loc)
    # --------------------------------------------------------------------------
    def SetFormat(self, format):
        self.format = format
        self.sComma = ","
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        l.append(stylesheet.sKeyword(self.sPrint),nIndentNext=1)
        if type(self.format)==StringType:
            l.append(self.format)
        elif type(self.format)==IntType:
            l.append(`self.format`)
        else:
            stylesheet.ToList(self.format, l)
        if not self.sComma: return 
        l.append(self.sComma)
        self.lIO.ToList(stylesheet, l) class Close(BasicIOList):
    # Stores a close statement
    def __init__(self, sLabel=None, loc=None, nIndent=0,
                 sClose="CLOSE", sParOpen='(', nUnit=None):
        BasicIOList.__init__(self, sLabel, loc, nIndent, sClose, sParOpen)
        if nUnit:
            self.AddIOOpt(nUnit) class SubroutineStatement(BasicStatement):
    def __init__(self, loc=None, lPrefix=[], sSub="SUBROUTINE", sName="",
                 nIndent=0, oSub = None):
        BasicStatement.__init__(self, None, loc, nIndent)
        self.lPrefix     = lPrefix
        self.sSub        = sSub
        self.sName       = sName
        self.lArgs       = DoubleList()
        self.sParOpen    = None
        self.sParClose   = None
        self.oSub        = oSub
    # --------------------------------------------------------------------------
    def SetParOpen(self, sParOpen): self.sParOpen = sParOpen
    # --------------------------------------------------------------------------
    def SetParClose(self, sParClose): self.sParClose = sParClose
    # --------------------------------------------------------------------------
    def GetName(self): return self.sName
    # --------------------------------------------------------------------------
    def GetPrefix(self): return self.lPrefix
    # --------------------------------------------------------------------------
    def GetArguments(self): return self.lArgs.GetMainList()
    # --------------------------------------------------------------------------
    def AddArgument(self, sName, sComma=None, d=None):
        if self.sParOpen==None: self.sParOpen="("
        self.sParClose = ")"
        if sComma==None and \
               len(self.lArgs.lGetSecondaryList())==len(self.lArgs)-1:
            self.lArgs.append(",", sName)
        else:
            self.lArgs.append(sName, sComma)
            
        if self.oSub:
            self.oSub.AddArgument(sName, sComma=sComma, d=d)
            
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        for i in self.lPrefix:
            l.append(stylesheet.sKeyword(i), nIndentNext=1)
        l.append(stylesheet.sKeyword(self.sSub), nIndentNext=1)
        l.append(self.sName)
        if not self.sParOpen:
            return 
        l.append(self.sParOpen)
        self.lArgs.ToList(stylesheet, l)
        l.append(self.sParClose)
                 
    # -------------------------------------------------------------------------- class Subroutine(ProgUnit):
    # Constructor for a subroutine object. Parameter:
    #
    # sSubName -- Name of function
    #
    def __init__(self, subStatement=None):
        ProgUnit.__init__(self, subStatement) class ProgramStatement(SubroutineStatement):
    def __init__(self, loc=None, lPrefix=[], sSub="PROGRAM", sName="",
                 nIndent=0, oSub = None):
        SubroutineStatement.__init__(self, loc=loc, lPrefix=lPrefix, sSub=sSub,
                                     sName=sName, nIndent=nIndent, oSub=oSub) class Program(ProgUnit):
    # Constructor for a program object. Parameter:
    #
    # sProgName -- Name of function
    #
    def __init__(self, progStatement=None):
        ProgUnit.__init__(self, progStatement) class EndProgUnit(BasicStatement):

    # Stores an end-{program, subroutine, function} statement:
    # end-program-stmt	is END [ PROGRAM [ program-name ] ]
    # end-subroutine-stmt is END [ SUBROUTINE [ subroutine-name ] ]
    # end-function-stmt	is END [ FUNCTION [ function-name ] ]
    def __init__(self, sLabel=None, loc=None, sEnd="END", nIndent=0, sName=None):
        self.sEnd  = sEnd
        self.sType = None
        self.sName = sName
        BasicStatement.__init__(self, sLabel, loc, nIndent)
    # --------------------------------------------------------------------------
    # Is sName is none, only 'subroutine' will be appended
    def SetName(self, sType, sName=None):
        self.sType = sType
        self.sName = sName
    # --------------------------------------------------------------------------
    def ToList(self, stylesheet, l):
        BasicStatement.ToList(self, stylesheet, l)
        l.append(stylesheet.sKeyword(self.sEnd))
        if self.sType: l.append(stylesheet.sKeyword(self.sType), nIndent=1)
        if self.sName: l.append(self.sName,                      nIndent=1)
import sys
import getopt
import string
import copy
from   os.path         import basename, splitext
from   Tools.Project   import Project
from   Tools.VarUsage  import VarUsage
from   Grammar.Parser  import Parser
from   Stylesheets.f77 import f77
from   Stylesheets.Default import DefaultStylesheet
from   AOR.Declaration import Declaration, VariableWithInit, Include
from   AOR.Expression  import Expression, Literal, ArraySpecWithName, TrueFalse
from   AOR.Variable    import VariableData, Variable
from   AOR.Statements  import Allocate, Call, Assignment, Stop, FunctionCall, \
                              Return
from   AOR.Do          import ControlLessDo, Exit, EndDo,Do
from   AOR.If          import IfOnly, If, EndIf
from   AOR.IO          import Write, Read, Open, Print, Close
from   AOR.Subroutine  import SubroutineStatement, Subroutine
from   AOR.Program     import ProgramStatement, Program
from   AOR.ProgUnit    import EndProgUnit
        
        oCompare    = Expression(oAbs,">",self.sVar("fmax"))
        lMain.append(If(oIfCond=oCompare))                         #  if(abs(a(i)-b(i))>fmax)
        
        lMain.append(Assignment(lhs=self.sVar("fmax"), rhs=oAbs))  #   fmax=abs(a(i)-b(i))
        
        for i in range(nDim):                                   
            lMain.append(Assignment(lhs=self.sVar("ubound%d"%i),   #   ubound0 = i
                                    rhs="%s%d"%(sLoopVar,i)))
        lMain.append(EndIf())                                      #  endif
        lMain.append(EndIf())                                      # endif
       
    # --------------------------------------------------------------------------
    def AppendCheckLogical(self, lMain, oNew, oCorrect, nDim, sLoopVar):
        oCompare    = Expression(oNew,".neqv.",oCorrect)
        lMain.append(If(oIfCond=oCompare))                         # if(a .ne. b) then
        
        exp = Expression(Variable(self.sVar("errcount")), "+","1") 
        lMain.append(Assignment(lhs=self.sVar("errcount"),rhs=exp))#  errcount=errcount+1
        
        for i in range(nDim):                                   
            lMain.append(Assignment(lhs=self.sVar("ubound%d"%i),   #   ubound0 = i
                                    rhs="%s%d"%(sLoopVar,i)))
        lMain.append(EndIf())                                      # endif
    # --------------------------------------------------------------------------
    def AppendCheckOther(self, lMain, oNew, oCorrect, nDim, sLoopVar):
        oCompare    = Expression(oNew,".ne.",oCorrect)
        lMain.append(If(oIfCond=oCompare))                         # if(a .ne. b) then
        
        exp = Expression(Variable(self.sVar("errcount")), "+","1") 
        lMain.append(Assignment(lhs=self.sVar("errcount"),rhs=exp))#  errcount=errcount+1
        
        for i in range(nDim):                                   
            lMain.append(Assignment(lhs=self.sVar("ubound%d"%i),   #   ubound0 = i
                                    rhs="%s%d"%(sLoopVar,i)))
        lMain.append(EndIf())                                      # endif

    # --------------------------------------------------------------------------
    # Appends code to check all elements of one array, and print out the
    # maximum error (if any), and number of errors
    def AppendCheckOneArray(self, lMain, oVar, sLoopVar):
        nDim = oVar["dimension"].nGetNumberOfDimensions()
        lMain.append(Assignment(lhs=self.sVar("fmax"),rhs="0.0"))
        lMain.append(Assignment(lhs=self.sVar("errcount"),rhs="0"))

        # Add all outer loops
        # -------------------
        for i in range(nDim):
            do = Do(var="%s%d"%(sLoopVar, nDim-i-1),
                    sFrom="lbound(%s,%d)"%(oVar, nDim-i),
                    sTo="ubound(%s,%d)"%(oVar, nDim-i)   )
            lMain.append(do)
            
        oNew     = ArraySpecWithName(var=oVar)
        oCorrect = ArraySpecWithName(self.sCorrectVar(oVar))
        for i in range(nDim):
            oNew.AddSubscript("%s%d"%(sLoopVar,i))
            oCorrect.AddSubscript("%s%d"%(sLoopVar,i))
        
        # Check for maximum error
        # -----------------------
        
        # We have to create real objects here (instead of making one string
        # which contains the comparison), since otherwise the expression is
        # too long and the stylesheet can't split the line
        sType = `oVar["type"]`.lower()
        if sType=="real" or sType=="integer" or sType=="complex" or \
           sType=="doubleprecision":
            self.AppendCheckNumerical(lMain, oNew, oCorrect, nDim, sLoopVar)
        elif (sType=="logical"):
            self.AppendCheckLogical(lMain, oNew, oCorrect, nDim, sLoopVar)
        else:
            self.AppendCheckOther(lMain, oNew, oCorrect, nDim, sLoopVar)

        # Add all EndDos for loops
        # ------------------------
        for i in range(nDim):
            lMain.append(EndDo())

        oIf = If(oIfCond="%s>0"%(self.sVar("errcount")))
        lMain.append(oIf)
        pr= Print(format="*")
        pr.AddIOExpression("\"%s: error: %s, number of errors:\""%(self.sDumpPrefix, `oVar`))
        pr.AddIOExpression(self.sVar("errcount"))
        lMain.append(pr)

        oNew     = ArraySpecWithName(var=oVar)
        oCorrect = ArraySpecWithName(self.sCorrectVar(oVar))
        lIndices = []
        for i in range(nDim):
            s = self.sVar("ubound%d"%i)
            oNew.AddSubscript(s)
            oCorrect.AddSubscript(s)
            lIndices.append(s)
            
        pr= Print(format="*")
        pr.AddIOExpression("\"%s: correct\""%self.sDumpPrefix)
        pr.AddIOExpression(oCorrect)
        lMain.append(pr)
        
        pr= Print(format="*")
        pr.AddIOExpression("\"%s: is     \""%self.sDumpPrefix)
        pr.AddIOExpression(oNew)
        lMain.append(pr)

        pr= Print(format="*")
        pr.AddIOExpression("\"%s: at     \""%self.sDumpPrefix)
        for i in lIndices:
            pr.AddIOExpression(i)
        lMain.append(pr)

        lMain.append(EndIf())

    # --------------------------------------------------------------------------
    def AppendResultCheck(self, lDecl, lMain):

        # Check all scalar variables
        # --------------------------
        for i in self.lWriteScalars:
            sCorrect=self.sCorrectVar(i)

            pr = Print(format="*")