Coverage for skema/program_analysis/CAST/fortran/preprocessor/fixed2free.py: 58%

100 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-04-30 17:15 +0000

1#!/usr/bin/python 

2# -*- coding: utf-8 -*- 

3# 

4# fixed2free2.py: Conversion of Fortran code from fixed to free 

5# source form. 

6# 

7# Copyright (C) 2012 Elias Rabel 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21 

22""" 

23Script that converts fixed form Fortran code to free form 

24Usage: file name as first command line parameter 

25 

26python fixed2free2.py file.f > file.f90 

27""" 

28 

29# author: Elias Rabel, 2012 

30# Let me know if you find this script useful: 

31# ylikx.0 at gmail 

32# https://www.github.com/ylikx/ 

33 

34# TODO: 

35# *) Improve command line usage 

36 

37# Modifications by vincentraymond-ua 

38# Convert tab-form lines that have been changed to a single space by GCC to free-form before processing 

39 

40from __future__ import print_function 

41import sys 

42 

43class FortranLine: 

44 def __init__(self, line): 

45 self.line = line 

46 self.line_conv = line 

47 self.isComment = False 

48 self.isContinuation = False 

49 self.__analyse() 

50 

51 def __repr__(self): 

52 return self.line_conv 

53 

54 def continueLine(self): 

55 """Insert line continuation symbol at correct position in a free format line.""" 

56 if not self.isOMP: 

57 before_inline_comment, inline_comment = extract_inline_comment(self.line_conv) 

58 else: 

59 tmp, inline_comment = extract_inline_comment(self.line_conv[1:].lstrip()) 

60 before_inline_comment = "!" + tmp 

61 

62 if inline_comment == "": 

63 self.line_conv = self.line_conv.rstrip() + " &\n" 

64 else: 

65 len_before = len(before_inline_comment) 

66 before = before_inline_comment.rstrip() + " & " 

67 self.line_conv = before.ljust(len_before) + inline_comment 

68 

69 def __analyse(self): 

70 line = self.line 

71 # MODIFICATION: Handle tabs that have been converted to spaces by GCC 

72 if line[0] == " " and line[1] != " ": 

73 line = " " + line[1:] 

74 

75 firstchar = line[0] if len(line) > 0 else '' 

76 self.label = line[0:5].strip().lower() + ' ' if len(line) > 1 else '' 

77 cont_char = line[5] if len(line) >= 6 else '' 

78 fivechars = line[1:5] if len(line) > 1 else '' 

79 self.isShort = (len(line) <= 6) 

80 self.isLong = (len(line) > 73) 

81 

82 

83 self.isComment = firstchar in "cC*!" 

84 self.isNewComment = '!' in fivechars and not self.isComment 

85 self.isOMP = self.isComment and fivechars.lower() == "$omp" 

86 if self.isOMP: 

87 self.isComment = False 

88 self.label = '' 

89 self.isCppLine = (firstchar == '#') 

90 self.is_regular = (not (self.isComment or self.isNewComment or 

91 self.isCppLine or self.isShort)) 

92 self.isContinuation = (not (cont_char.isspace() or cont_char == '0') and 

93 self.is_regular) 

94 

95 self.code = line[6:] if len(line) > 6 else '\n' 

96 

97 self.excess_line = '' 

98 if self.isLong and self.is_regular: 

99 code, inline_comment = extract_inline_comment(self.code) 

100 if inline_comment == "" or len(code) >= 72 - 6: 

101 self.excess_line = line[72:] 

102 line = line[:72] + '\n' 

103 self.code = line[6:] 

104 

105 self.line = line 

106 self.__convert() 

107 

108 def __convert(self): 

109 line = self.line 

110 

111 if self.isComment: 

112 self.line_conv = '!' + line[1:] 

113 elif self.isNewComment or self.isCppLine: 

114 self.line_conv = line 

115 elif self.isOMP: 

116 self.line_conv = '!' + line[1:5] + ' ' + self.code 

117 elif not self.label.isspace(): 

118 self.line_conv = self.label + self.code 

119 else: 

120 self.line_conv = self.code 

121 

122 if self.excess_line != '': 

123 if self.excess_line.lstrip().startswith("!"): 

124 marker = "" 

125 else: 

126 marker = "!" 

127 

128 self.line_conv = self.line_conv.rstrip().ljust(72) + marker + self.excess_line 

129 

130def extract_inline_comment(code): 

131 """Splits line of code into (code, inline comment)""" 

132 stringmode = False 

133 stringchar = "" 

134 

135 for column, character in enumerate(code): 

136 is_string_delimiter = (character == "'" or character == '"') 

137 if not stringmode and is_string_delimiter: 

138 stringmode = True 

139 stringchar = character 

140 elif stringmode and is_string_delimiter: 

141 stringmode = (character != stringchar) 

142 elif not stringmode and character == "!": 

143 return code[:column], code[column:] 

144 

145 return code, "" 

146 

147 

148def convertToFree(stream): 

149 """Convert stream from fixed source form to free source form.""" 

150 linestack = [] 

151 

152 for line in stream: 

153 convline = FortranLine(line) 

154 

155 if convline.is_regular: 

156 if convline.isContinuation and linestack: 

157 linestack[0].continueLine() 

158 for l in linestack: 

159 yield str(l) 

160 linestack = [] 

161 

162 linestack.append(convline) 

163 

164 for l in linestack: 

165 yield str(l) 

166 

167 

168if __name__ == "__main__": 

169 

170 if len(sys.argv) > 1: 

171 infile = open(sys.argv[1], 'r') 

172 for line in convertToFree(infile): 

173 print(line, end="") 

174 

175 infile.close() 

176 else: 

177 print(__doc__)