irpf90/src/parsed_text.py

367 lines
12 KiB
Python

#!/usr/bin/python
# IRPF90 is a Fortran90 preprocessor written in Python for programming using
# the Implicit Reference to Parameters (IRP) method.
# Copyright (C) 2009 Anthony SCEMAMA
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Anthony Scemama
# LCPQ - IRSAMC - CNRS
# Universite Paul Sabatier
# 118, route de Narbonne
# 31062 Toulouse Cedex 4
# scemama@irsamc.ups-tlse.fr
from util import *
from irpf90_t import *
from variables import variables
from preprocessed_text import preprocessed_text
from subroutines import subroutines
import regexps
import error
def find_variables_in_line(line):
assert isinstance(line,Line)
result = []
sub_done = False
buffer = line.text.lower()
for v in variables.keys():
var = variables[v]
if var.name in buffer:
if not sub_done:
buffer = regexps.re_string.sub('',buffer)
sub_done = True
if var.regexp.search(buffer) is not None:
result.append(var.same_as)
return result
def find_subroutine_in_line(line):
assert isinstance(line,Call)
buffer = line.text.split('(')[0]
buffer = buffer.split()[1]
return buffer
def check_touch(line,vars,main_vars):
def fun(main_var):
if main_var not in variables:
error.fail(line,"Variable %s unknown"%(main_var,))
x = variables[main_var]
return [main_var]+x.others
all_others = make_single(flatten( map(fun,main_vars) ))
all_others.sort()
if len(all_others) == len(vars):
vars.sort()
for x,y in zip(vars,all_others):
if x != y:
message = "The following entities should be touched:\n"
message = "\n".join([message]+map(lambda x: "- %s"%(x,),all_others))
error.fail(line,message)
def get_parsed_text():
main_result = []
varlist = []
for filename, text in preprocessed_text:
result = []
for line in filter(
lambda x: type(x) not in [ Doc, Begin_doc, End_doc ],
text):
if type(line) in [ \
Empty_line,
Continue,
Return,
Begin_shell,
End_shell,
Openmp,
Use,
Enddo,
End_select,
Endif,
Implicit,
Program,
Subroutine,
Function,
End,
]:
result.append( ([],line) )
elif isinstance(line,End_provider):
varlist = []
result.append( ([],line) )
elif isinstance(line,Provide):
l = line.text.lower().split()[1:]
l = filter(lambda x: x not in varlist, l)
for v in l:
if v not in variables.keys():
error.fail(line,"Variable %s is unknown"%(v))
result.append( (l,Simple_line(line.i,"!%s"%(line.text),line.filename)) )
elif isinstance(line,Call):
sub = find_subroutine_in_line(line)
if sub not in subroutines:
t = Simple_line
else:
if subroutines[sub].touches == []:
t = Simple_line
else:
t = Provide_all
l = find_variables_in_line(line)
l = filter(lambda x: x not in varlist, l)
result.append( (l,t(line.i,line.text,line.filename)) )
elif isinstance(line,Free):
vars = line.text.split()
if len(vars) < 2:
error.fail(line,"Syntax error")
vars = map(lower,vars[1:])
for v in vars:
variables[v].is_freed = True
result.append( ([],Simple_line(line.i,"!%s"%(line.text),line.filename)) )
use = map(lambda x: " use %s"%(variables[x].fmodule),vars)
for var in vars:
result += map(lambda x: ([],Use(line.i,x,line.filename)),
make_single(use))
result += map(lambda x: ([],Simple_line(line.i,x,line.filename)),
variables[var].free)
elif isinstance(line,Irp_read):
variables[line.filename].is_read = True
result.append( ([],Simple_line(line.i,"!%s"%(line.text),line.filename)) )
elif isinstance(line,Irp_write):
variables[line.filename].is_written = True
result.append( ([],Simple_line(line.i,"!%s"%(line.text),line.filename)) )
elif isinstance(line,Touch):
vars = line.text.split()
if len(vars) < 2:
error.fail(line,"Syntax error")
vars = map(lower,vars[1:])
for v in vars:
if v not in variables:
error.fail(line,"Variable %s unknown"%(v,))
variables[v]._is_touched = True
def fun(x):
main = variables[x].same_as
return main
main_vars = make_single( map(fun, vars) )
check_touch(line,vars,main_vars)
txt = " ".join(vars)
result += [ (vars,Simple_line(line.i,"!",line.filename)),
([],Simple_line(line.i,"! >>> TOUCH %s"%(txt,),line.filename)) ]
def fun(x):
if x not in variables:
error.fail(line,"Variable %s unknown"%(x,))
return [ ([],Simple_line(line.i," call touch_%s"%(x,),line.filename)),
([],Use(line.i," use %s"%(variables[x].fmodule), line.filename)) ]
result += flatten(map( fun, main_vars ))
def fun(x):
if x not in variables:
error.fail(line,"Variable %s unknown"%(x,))
return ([],Simple_line(line.i," %s_is_built = .True."%(x,),line.filename))
result += map( fun, main_vars[:-1] )
result += [ ([],Provide_all(line.i,"! <<< END TOUCH",line.filename)) ]
elif type(line) in [ Begin_provider, Cont_provider ]:
if isinstance(line,Begin_provider):
varlist = []
buffer = map(strip,line.text.replace(']','').split(','))
assert len(buffer) > 1
v = buffer[1].lower()
varlist.append(v)
variable_list = find_variables_in_line(line)
variable_list.remove(variables[v].same_as)
result.append( (variable_list,line) )
else:
l = find_variables_in_line(line)
l = filter(lambda x: x not in varlist, l)
result.append( (l,line) )
main_result.append( (filename, result) )
return main_result
parsed_text = get_parsed_text()
######################################################################
def move_variables():
main_result = []
for filename, text in parsed_text:
result = []
# 1st pass
varlist = []
ifvars = []
elsevars = []
old_varlist = []
old_ifvars = []
old_elsevars = []
revtext = list(text)
revtext.reverse()
for vars,line in revtext:
if type(line) in [ End_provider,End ]:
varlist = []
result.append( ([],line) )
elif type(line) in [ Endif, End_select ]:
old_ifvars.append(ifvars)
old_elsevars.append(elsevars)
old_varlist.append(varlist)
varlist = []
result.append( ([],line) )
elif type(line) == Else:
result.append( (varlist,line) )
elsevars = list(varlist)
if vars != []:
varlist = old_varlist.pop()
varlist += vars
old_varlist.append(varlist)
varlist = []
elif type(line) in [ Elseif, Case ]:
ifvars += varlist
result.append( (varlist,line) )
if vars != []:
varlist = old_varlist.pop()
varlist += vars
old_varlist.append(varlist)
varlist = []
elif type(line) in [ If, Select ]:
ifvars += varlist
result.append( (varlist,line) )
vars += filter(lambda x: x in elsevars, ifvars)
ifvars = old_ifvars.pop()
elsevars = old_elsevars.pop()
varlist = old_varlist.pop()
varlist += vars
elif type(line) in [ Begin_provider, Subroutine, Function ]:
varlist += vars
result.append( (varlist,line) )
assert old_varlist == []
assert old_ifvars == []
assert old_elsevars == []
varlist = []
elif isinstance(line,Provide_all):
result.append( (vars,line) )
else:
varlist += vars
result.append( ([],line) )
result.reverse()
# 2nd pass
text = result
result = []
old_varlist = []
varlist = []
for vars,line in text:
if vars != []:
vars = make_single(vars)
if type(line) in [ Begin_provider, Subroutine, Function ]:
varlist = list(vars)
elif type(line) in [ If, Select ]:
old_varlist.append(varlist)
vars = filter(lambda x: x not in varlist,vars)
varlist = make_single(varlist + vars)
assert old_varlist is not varlist
elif type(line) in [ Elseif, Else, Case ]:
varlist = old_varlist.pop()
old_varlist.append(varlist)
vars = filter(lambda x: x not in varlist,vars)
varlist = make_single(varlist + vars)
assert old_varlist is not varlist
elif type(line) in [ Endif, End_select ]:
varlist = old_varlist.pop()
elif type(line) == Provide_all:
vars = varlist
elif type(line) in [ End_provider, End ]:
assert old_varlist == []
varlist = []
result.append( (vars,line) )
main_result.append( (filename, result) )
return main_result
parsed_text = move_variables()
######################################################################
def move_to_top(text,t):
assert isinstance(text,list)
assert t in [ Declaration, Implicit, Use, Cont_provider ]
inside = False
for i in range(len(text)):
vars, line = text[i]
if type(line) in [ Begin_provider, Subroutine, Function ]:
begin = i
inside = True
elif type(line) in [ End_provider, End ]:
inside = False
elif isinstance(line,t):
if inside:
text.pop(i)
begin += 1
text.insert(begin,(vars,line))
return text
######################################################################
def build_needs():
# Needs
for filename, text in parsed_text:
var = None
for vars,line in text:
if isinstance(line,Begin_provider):
buffer = map(strip,line.text.replace(']',',').split(','))
var = variables[buffer[1].lower()]
var.needs = []
var.to_provide = vars
elif isinstance(line,End_provider):
var.needs = make_single(var.needs)
var.to_provide = make_single(var.to_provide)
var = None
if var is not None:
var.needs += vars
for v in variables.keys():
main = variables[v].same_as
if main != v:
variables[v].needs = variables[main].needs
variables[v].to_provide = variables[main].to_provide
# Needed_by
for v in variables.keys():
variables[v].needed_by = []
for v in variables.keys():
main = variables[v].same_as
if main != v:
variables[v].needed_by = variables[main].needed_by
for v in variables.keys():
var = variables[v]
if var.is_main:
for x in var.needs:
variables[x].needed_by.append(var.same_as)
for v in variables.keys():
var = variables[v]
var.needed_by = make_single(var.needed_by)
build_needs()
result = []
for filename,text in parsed_text:
text = move_to_top(text,Declaration)
text = move_to_top(text,Implicit)
text = move_to_top(text,Use)
text = move_to_top(text,Cont_provider)
result.append ( (filename,text) )
parsed_text = result
######################################################################
if __name__ == '__main__':
for i in range(len(parsed_text)):
if parsed_text[i][0] == 'vmc_step.irp.f':
print '!-------- %s -----------'%(parsed_text[i][0])
for line in parsed_text[i][1]:
print line[1]
print line[0], line[1].filename