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
« 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/>.
22"""
23Script that converts fixed form Fortran code to free form
24Usage: file name as first command line parameter
26python fixed2free2.py file.f > file.f90
27"""
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/
34# TODO:
35# *) Improve command line usage
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
40from __future__ import print_function
41import sys
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()
51 def __repr__(self):
52 return self.line_conv
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
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
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:]
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)
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)
95 self.code = line[6:] if len(line) > 6 else '\n'
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:]
105 self.line = line
106 self.__convert()
108 def __convert(self):
109 line = self.line
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
122 if self.excess_line != '':
123 if self.excess_line.lstrip().startswith("!"):
124 marker = ""
125 else:
126 marker = "!"
128 self.line_conv = self.line_conv.rstrip().ljust(72) + marker + self.excess_line
130def extract_inline_comment(code):
131 """Splits line of code into (code, inline comment)"""
132 stringmode = False
133 stringchar = ""
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:]
145 return code, ""
148def convertToFree(stream):
149 """Convert stream from fixed source form to free source form."""
150 linestack = []
152 for line in stream:
153 convline = FortranLine(line)
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 = []
162 linestack.append(convline)
164 for l in linestack:
165 yield str(l)
168if __name__ == "__main__":
170 if len(sys.argv) > 1:
171 infile = open(sys.argv[1], 'r')
172 for line in convertToFree(infile):
173 print(line, end="")
175 infile.close()
176 else:
177 print(__doc__)