Strip block comments: Difference between revisions

→‎{{header|F_Sharp|F#}}: Add Fortran. Before F_?
mNo edit summary
(→‎{{header|F_Sharp|F#}}: Add Fortran. Before F_?)
Line 564:
# and bananas; and bananas </pre>
 
 
=={{header|Fortran}}==
As ever, there arises the question "How long is a piece of string?" as having once abandoned decks of cards, there is no longer a definite upper bound for the length of a record. So, as ever, the classic response of "surely big enough", here 6666 characters. F90 enables the creation of a protocol for varying-length strings, and F2000 formalises this, but, there is no provision for reading a record of input into a variable that is made large enough for the record just being read, as is almost the case for pl/1 - where the receiving variable would be declared <code>ACARD CHARACTER(6666) VARYING</code> and the READ statement sets the length according to what has been read - but only up to the pre-specified upper limit.
 
So, a reversion to F77 style (which introduced CHARACTER variables) and so, not employing the MODULE protocol of F90 to share information - COMMON statements instead. Though not purely F77 as there is the PARAMETER statement, and the usage of I0 format.
 
If the text delimiters were single characters only, similar to text literals, it would be easy: scan the text character by character and change state accordingly, though there would be complications if say two quote characters in a row were to signify a single internal quote. A DO-loop would do for the scan. But with multi-character delimiters the scan would have to lurch over a match, and fiddling the index variable of a DO-loop is frowned upon. So instead, slog it out. And be annoyed afresh by the indeterminacy of boolean expression evaluation of the form A '''and''' B or A '''or''' B in the context where the test is ''safe'' '''and''' ''test'' because the test might provoke an out-of-bounds fault if not safely within bounds. Like, THIS is being tested against the text in ACARD, but it must not compare beyond the end of the text in ACARD.
 
The removal of delimited text is taken literally: an incoming card's content might be entirely within a block comment and so be entirely rejected; if so, a null line results in ALINE, and it is ''not'' written to the output file. In other words, lines of block comment are not preserved as blank lines, nor as null lines, they are not there. Only if a line contains text outside of a block comment will it survive. Outside delimited block comments, spaces are just as valid as any other symbol, and are preserved. So, for example, it is <code>a = b + c ;</code> not <code>a = b + c ;</code> - two spaces after the = sign. Similarly, trailing spaces on a line survive - though I have UltraEdit set to trim trailing spaces and it is not clear whether the example source is to be regarded as containing them or not.
 
A feature of Fortran's character comparison is that trailing spaces are ignored, so that "x " and "x " and "x" are all deemed equal. Unfortunate choices of starting and ending delimiter texts can be made if they contain characters in common.
 
<lang Fortran>
SUBROUTINE UNBLOCK(THIS,THAT) !Removes block comments bounded by THIS and THAT.
Copies from file INF to file OUT, record by record, except skipping null output records.
CHARACTER*(*) THIS,THAT !Starting and ending markers.
INTEGER LOTS !How long is a piece of string?
PARAMETER (LOTS = 6666) !This should do.
CHARACTER*(LOTS) ACARD,ALINE !Scratchpads.
INTEGER LC,LL,L !Lengths.
INTEGER L1,L2 !Scan fingers.
INTEGER NC,NL !Might as well count records read and written.
LOGICAL BLAH !A state: in or out of a block comment.
INTEGER MSG,KBD,INF,OUT !I/O unit numbers.
COMMON /IODEV/MSG,KBD,INF,OUT !Thus.
NC = 0 !No cards read in.
NL = 0 !No lines written out.
BLAH = .FALSE. !And we're not within a comment.
Chug through the input.
10 READ(INF,11,END = 100) LC,ACARD(1:MIN(LC,LOTS)) !Yum.
11 FORMAT (Q,A) !Sez: how much remains (Q), then, characters (A).
NC = NC + 1 !A card has been read.
IF (LC.GT.LOTS) THEN !Paranoia.
WRITE (MSG,12) NC,LC,LOTS !Scream.
12 FORMAT ("Record ",I0," has length ",I0,"! My limit is ",I0)
LC = LOTS !Stay calm, and carry on.
END IF !None of this should happen.
Chew through ACARD according to mood.
LL = 0 !No output yet.
L2 = 0 !Syncopation. Where the previous sniff ended.
20 L1 = L2 + 1 !The start of what we're looking at.
IF (L1.LE.LC) THEN !Anything left?
L2 = L1 !Yes. This is the probe.
IF (BLAH) THEN !So, what's our mood?
21 IF (L2 + LEN(THAT) - 1 .LE. LC) THEN !We're skipping stuff.
IF (ACARD(L2:L2 + LEN(THAT) - 1).EQ.THAT) THEN !An ender yet?
BLAH = .FALSE. !Yes!
L2 = L2 + LEN(THAT) - 1 !Finger its final character.
GO TO 20 !And start a new advance.
END IF !But if that wasn't an ender,
L2 = L2 + 1 !Advance one.
GO TO 21 !And try again.
END IF !By here, insufficient text remains to match THAT, so we're finished with ACARD.
ELSE !Otherwise, if we're not in a comment, we're looking at grist.
22 IF (L2 + LEN(THIS) - 1 .LE. LC) THEN !Enough text to match a comment starter?
IF (ACARD(L2:L2 + LEN(THIS) - 1).EQ.THIS) THEN !Yes. Does it?
BLAH = .TRUE. !Yes!
L = L2 - L1 !Recalling where this state started.
ALINE(LL + 1:LL + L) = ACARD(L1:L2 - 1) !Copy the non-BLAH text.
LL = LL + L !L2 fingers the first of THIS.
L2 = L2 + LEN(THIS) - 1 !Finger the last matching THIS.
GO TO 20 !And resume.
END IF !But if that wasn't a comment starter,
L2 = L2 + 1 !Advance one.
GO TO 22 !And try again.
END IF !But if there remains insufficient to match THIS
L = LC - L1 + 1 !Then the remainder of the line is grist.
ALINE(LL + 1:LL + L) = ACARD(L1:LC) !So grab it.
LL = LL + L !And count it in.
END IF !By here, we're finished witrh ACARD.
END IF !So much for ACARD.
Cast forth some output.
IF (LL.GT.0) THEN !If there is any.
WRITE (OUT,23) ALINE(1:LL) !There is.
23 FORMAT (A) !Just text.
NL = NL + 1 !Count a line.
END IF !So much for output.
GO TO 10 !Perhaps there is some more input.
Completed.
100 WRITE (MSG,101) NC,NL !Be polite.
101 FORMAT (I0," read, ",I0," written.")
END
 
PROGRAM TEST
INTEGER MSG,KBD,INF,OUT
COMMON /IODEV/MSG,KBD,INF,OUT
KBD = 5
MSG = 6
INF = 10
OUT = 11
OPEN (INF,FILE="Source.txt",STATUS="OLD",ACTION="READ")
OPEN (OUT,FILE="Src.txt",STATUS="REPLACE",ACTION="WRITE")
 
CALL UNBLOCK("/*","*/")
 
END !All open files are closed on exit..
</lang>
Output: 16 read, 8 written. And in the output file appears...
<pre>
function subroutine() {
a = b + c ;
}
function something() {
}
</pre>
 
=={{header|F_Sharp|F#}}==
1,220

edits