Compiler/lexical analyzer: Difference between revisions
Content added Content deleted
Line 15,114: | Line 15,114: | ||
23 1 End_of_input |
23 1 End_of_input |
||
</pre> |
</pre> |
||
=={{header|RATFOR}}== |
|||
{{works with|ratfor77|[https://sourceforge.net/p/chemoelectric/ratfor77/ public domain 1.0]}} |
|||
{{works with|gfortran|11.2.1}} |
|||
{{works with|f2c|20100827}} |
|||
<lang ratfor>###################################################################### |
|||
# |
|||
# The Rosetta Code scanner in Ratfor 77. |
|||
# |
|||
# |
|||
# How to deal with FORTRAN 77 input is a problem. I use formatted |
|||
# input, treating each line as an array of type CHARACTER--regrettably |
|||
# of no more than some predetermined, finite length. It is a very |
|||
# simple method and presents no significant difficulties, aside from |
|||
# the restriction on line length of the input. |
|||
# |
|||
# |
|||
# On a POSIX platform, the program can be compiled with f2c and run |
|||
# somewhat as follows: |
|||
# |
|||
# ratfor77 lex-in-ratfor.r > lex-in-ratfor.f |
|||
# f2c -C -Nc40 lex-in-ratfor.f |
|||
# cc -O lex-in-ratfor.c -lf2c |
|||
# ./a.out < compiler-tests/primes.t |
|||
# |
|||
# With gfortran, a little differently: |
|||
# |
|||
# ratfor77 lex-in-ratfor.r > lex-in-ratfor.f |
|||
# gfortran -O2 -fcheck=all -std=legacy lex-in-ratfor.f |
|||
# ./a.out < compiler-tests/primes.t |
|||
# |
|||
# |
|||
# I/O is strictly from default input and to default output, which, on |
|||
# POSIX systems, usually correspond respectively to standard input and |
|||
# standard output. (I did not wish to have to deal with unit numbers; |
|||
# these are now standardized in ISO_FORTRAN_ENV, but that is not |
|||
# available in FORTRAN 77.) |
|||
# |
|||
#--------------------------------------------------------------------- |
|||
# Some parameters you may with to modify. |
|||
define(LINESZ, 256) # Size of an input line. |
|||
define(OUTLSZ, 512) # Size of an output line. |
|||
define(PSHBSZ, 10) # Size of the character pushback buffer. |
|||
define(STRNSZ, 4096) # Size of the string pool. |
|||
#--------------------------------------------------------------------- |
|||
define(EOF, -1) |
|||
define(NEWLIN, 10) # Unix newline (the LF control character). |
|||
define(BACKSL, 92) # ASCII backslash. |
|||
define(ILINNO, 1) # Line number's index. |
|||
define(ICOLNO, 2) # Column number's index. |
|||
define(CHRSZ, 3) # See ILINNO and ICOLNO above. |
|||
define(ICHRCD, 3) # Character code's index. |
|||
define(TOKSZ, 5) # See ILINNO and ICOLNO above. |
|||
define(ITOKNO, 3) # Token number's index. |
|||
define(IARGIX, 4) # Index of the string pool index. |
|||
define(IARGLN, 5) # Index of the string length. |
|||
define(TKELSE, 0) |
|||
define(TKIF, 1) |
|||
define(TKPRNT, 2) |
|||
define(TKPUTC, 3) |
|||
define(TKWHIL, 4) |
|||
define(TKMUL, 5) |
|||
define(TKDIV, 6) |
|||
define(TKMOD, 7) |
|||
define(TKADD, 8) |
|||
define(TKSUB, 9) |
|||
define(TKNEG, 10) |
|||
define(TKLT, 11) |
|||
define(TKLE, 12) |
|||
define(TKGT, 13) |
|||
define(TKGE, 14) |
|||
define(TKEQ, 15) |
|||
define(TKNE, 16) |
|||
define(TKNOT, 17) |
|||
define(TKASGN, 18) |
|||
define(TKAND, 19) |
|||
define(TKOR, 20) |
|||
define(TKLPAR, 21) |
|||
define(TKRPAR, 22) |
|||
define(TKLBRC, 23) |
|||
define(TKRBRC, 24) |
|||
define(TKSEMI, 25) |
|||
define(TKCMMA, 26) |
|||
define(TKID, 27) |
|||
define(TKINT, 28) |
|||
define(TKSTR, 29) |
|||
define(TKEOI, 30) |
|||
define(LOC10, 1) # Location of "10" in the string pool. |
|||
define(LOC92, 3) # Location of "92" in the string pool. |
|||
#--------------------------------------------------------------------- |
|||
subroutine addstr (strngs, istrng, src, i0, n0, i, n) |
|||
# Add a string to the string pool. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character src(*) # Source string. |
|||
integer i0, n0 # Index and length in source string. |
|||
integer i, n # Index and length in string pool. |
|||
integer j |
|||
if (STRNSZ < istrng + (n0 - 1)) |
|||
{ |
|||
write (*, '(''string pool exhausted'')') |
|||
stop |
|||
} |
|||
for (j = 0; j < n0; j = j + 1) |
|||
strngs(istrng + j) = src(i0 + j) |
|||
i = istrng |
|||
n = n0 |
|||
istrng = istrng + n0 |
|||
end |
|||
subroutine cpystr (strngs, i, n, dst, i0) |
|||
# Copy a string from the string pool to an output string. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer i, n # Index and length in string pool. |
|||
character dst(OUTLSZ) # Destination string. |
|||
integer i0 # Index within destination string. |
|||
integer j |
|||
if (i0 < 1 || OUTLSZ < i0 + (n - 1)) |
|||
{ |
|||
write (*, '(''string boundary exceeded'')') |
|||
stop |
|||
} |
|||
for (j = 0; j < n; j = j + 1) |
|||
dst(i0 + j) = strngs(i + j) |
|||
end |
|||
#--------------------------------------------------------------------- |
|||
subroutine getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
# Get a character, with its line number and column number. |
|||
implicit none |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer chr(CHRSZ) |
|||
# End of file is indicated (as in C) by a negative "char code" |
|||
# called "EOF". |
|||
character*20 fmt |
|||
integer stat |
|||
integer chr1(CHRSZ) |
|||
if (0 < npshbk) |
|||
{ |
|||
chr(ICHRCD) = pushbk(ICHRCD, npshbk) |
|||
chr(ILINNO) = pushbk(ILINNO, npshbk) |
|||
chr(ICOLNO) = pushbk(ICOLNO, npshbk) |
|||
npshbk = npshbk - 1 |
|||
} |
|||
else if (colno <= LINESZ) |
|||
{ |
|||
chr(ICHRCD) = ichar (line(colno)) |
|||
chr(ILINNO) = linno |
|||
chr(ICOLNO) = colno |
|||
colno = colno + 1 |
|||
} |
|||
else |
|||
{ |
|||
# Return a newline character. |
|||
chr(ICHRCD) = NEWLIN |
|||
chr(ILINNO) = linno |
|||
chr(ICOLNO) = colno |
|||
# Fetch a new line. |
|||
linno = linno + 1 |
|||
colno = 1 |
|||
# Read a line of text as an array of characters. |
|||
write (fmt, '(''('', I10, ''A1)'')') LINESZ |
|||
read (*, fmt, iostat = stat) line |
|||
if (stat != 0) |
|||
{ |
|||
# If end of file has been reached, push an EOF. |
|||
chr1(ICHRCD) = EOF |
|||
chr1(ILINNO) = linno |
|||
chr1(ICOLNO) = colno |
|||
call pshchr (pushbk, npshbk, chr1) |
|||
} |
|||
} |
|||
end |
|||
subroutine pshchr (pushbk, npshbk, chr) |
|||
# Push back a character. |
|||
implicit none |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer chr(CHRSZ) |
|||
if (PSHBSZ <= npshbk) |
|||
{ |
|||
write (*, '(''pushback buffer overfull'')') |
|||
stop |
|||
} |
|||
npshbk = npshbk + 1 |
|||
pushbk(ICHRCD, npshbk) = chr(ICHRCD) |
|||
pushbk(ILINNO, npshbk) = chr(ILINNO) |
|||
pushbk(ICOLNO, npshbk) = chr(ICOLNO) |
|||
end |
|||
subroutine getpos (line, linno, colno, pushbk, npshbk, ln, cn) |
|||
# Get the position of the next character. |
|||
implicit none |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer ln, cn # The line and column nos. returned. |
|||
integer chr(CHRSZ) |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
ln = chr(ILINNO) |
|||
cn = chr(ICOLNO) |
|||
call pshchr (pushbk, npshbk, chr) |
|||
end |
|||
#--------------------------------------------------------------------- |
|||
function isspc (c) |
|||
# Is c character code for a space? |
|||
implicit none |
|||
integer c |
|||
logical isspc |
|||
# |
|||
# The following is correct for ASCII: 32 is the SPACE character, and |
|||
# 9 to 13 are control characters commonly regarded as spaces. |
|||
# |
|||
# In Unicode these are all code points for spaces, but so are others |
|||
# besides. |
|||
# |
|||
isspc = (c == 32 || (9 <= c && c <= 13)) |
|||
end |
|||
function isdgt (c) |
|||
# Is c character code for a digit? |
|||
implicit none |
|||
integer c |
|||
logical isdgt |
|||
isdgt = (ichar ('0') <= c && c <= ichar ('9')) |
|||
end |
|||
function isalph (c) |
|||
# Is c character code for a letter? |
|||
implicit none |
|||
integer c |
|||
logical isalph |
|||
# |
|||
# The following is correct for ASCII and Unicode, but not for |
|||
# EBCDIC. |
|||
# |
|||
isalph = (ichar ('a') <= c && c <= ichar ('z')) _ |
|||
|| (ichar ('A') <= c && c <= ichar ('Z')) |
|||
end |
|||
function isid0 (c) |
|||
# Is c character code for the start of an identifier? |
|||
implicit none |
|||
integer c |
|||
logical isid0 |
|||
logical isalph |
|||
isid0 = isalph (c) || c == ichar ('_') |
|||
end |
|||
function isid1 (c) |
|||
# Is c character code for the continuation of an identifier? |
|||
implicit none |
|||
integer c |
|||
logical isid1 |
|||
logical isalph |
|||
logical isdgt |
|||
isid1 = isalph (c) || isdgt (c) || c == ichar ('_') |
|||
end |
|||
#--------------------------------------------------------------------- |
|||
function trimlf (str, n) |
|||
# "Trim left" leading spaces. |
|||
implicit none |
|||
character str(*) # The string to "trim". |
|||
integer n # The length. |
|||
integer trimlf # The index of the first non-space |
|||
# character, or n + 1. |
|||
logical isspc |
|||
integer j |
|||
logical done |
|||
j = 1 |
|||
done = .false. |
|||
while (!done) |
|||
{ |
|||
if (j == n + 1) |
|||
done = .true. |
|||
else if (!isspc (ichar (str(j)))) |
|||
done = .true. |
|||
else |
|||
j = j + 1 |
|||
} |
|||
trimlf = j |
|||
end |
|||
function trimrt (str, n) |
|||
# "Trim right" trailing spaces. |
|||
implicit none |
|||
character str(*) # The string to "trim". |
|||
integer n # The length including trailing spaces. |
|||
integer trimrt # The length without trailing spaces. |
|||
logical isspc |
|||
integer j |
|||
logical done |
|||
j = n |
|||
done = .false. |
|||
while (!done) |
|||
{ |
|||
if (j == 0) |
|||
done = .true. |
|||
else if (!isspc (ichar (str(j)))) |
|||
done = .true. |
|||
else |
|||
j = j - 1 |
|||
} |
|||
trimrt = j |
|||
end |
|||
#--------------------------------------------------------------------- |
|||
subroutine toknam (tokno, str, i) |
|||
# Copy a token name to the character array str, starting at i. |
|||
implicit none |
|||
integer tokno |
|||
character str(*) |
|||
integer i |
|||
integer j |
|||
character*16 names(0:30) |
|||
character*16 nm |
|||
data names / "Keyword_else ", _ |
|||
"Keyword_if ", _ |
|||
"Keyword_print ", _ |
|||
"Keyword_putc ", _ |
|||
"Keyword_while ", _ |
|||
"Op_multiply ", _ |
|||
"Op_divide ", _ |
|||
"Op_mod ", _ |
|||
"Op_add ", _ |
|||
"Op_subtract ", _ |
|||
"Op_negate ", _ |
|||
"Op_less ", _ |
|||
"Op_lessequal ", _ |
|||
"Op_greater ", _ |
|||
"Op_greaterequal ", _ |
|||
"Op_equal ", _ |
|||
"Op_notequal ", _ |
|||
"Op_not ", _ |
|||
"Op_assign ", _ |
|||
"Op_and ", _ |
|||
"Op_or ", _ |
|||
"LeftParen ", _ |
|||
"RightParen ", _ |
|||
"LeftBrace ", _ |
|||
"RightBrace ", _ |
|||
"Semicolon ", _ |
|||
"Comma ", _ |
|||
"Identifier ", _ |
|||
"Integer ", _ |
|||
"String ", _ |
|||
"End_of_input " / |
|||
nm = names(tokno) |
|||
for (j = 0; j < 16; j = j + 1) |
|||
str(i + j) = nm(1 + j : 1 + j) |
|||
end |
|||
subroutine intstr (str, i, n, x) |
|||
# Convert a positive integer to a substring. |
|||
implicit none |
|||
character str(*) # Destination string. |
|||
integer i, n # Index and length of the field. |
|||
integer x # The positive integer to represent. |
|||
integer j |
|||
integer y |
|||
if (x == 0) |
|||
{ |
|||
for (j = 0; j < n - 1; j = j + 1) |
|||
str(i + j) = ' ' |
|||
str(i + j) = '0' |
|||
} |
|||
else |
|||
{ |
|||
y = x |
|||
for (j = n - 1; 0 <= j; j = j - 1) |
|||
{ |
|||
if (y == 0) |
|||
str(i + j) = ' ' |
|||
else |
|||
{ |
|||
str(i + j) = char (mod (y, 10) + ichar ('0')) |
|||
y = y / 10 |
|||
} |
|||
} |
|||
} |
|||
end |
|||
subroutine prttok (strngs, tok) |
|||
# Print a token. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer tok(TOKSZ) # The token. |
|||
integer trimrt |
|||
character line(OUTLSZ) |
|||
character*20 fmt |
|||
integer i, n |
|||
integer tokno |
|||
for (i = 1; i <= OUTLSZ; i = i + 1) |
|||
line(i) = ' ' |
|||
call intstr (line, 1, 10, tok(ILINNO)) |
|||
call intstr (line, 12, 10, tok(ICOLNO)) |
|||
tokno = tok(ITOKNO) |
|||
call toknam (tokno, line, 25) |
|||
if (tokno == TKID || tokno == TKINT || tokno == TKSTR) |
|||
{ |
|||
i = tok(IARGIX) |
|||
n = tok(IARGLN) |
|||
call cpystr (strngs, i, n, line, 45) |
|||
} |
|||
n = trimrt (line, OUTLSZ) |
|||
write (fmt, '(''('', I10, ''A)'')') n |
|||
write (*, fmt) (line(i), i = 1, n) |
|||
end |
|||
#--------------------------------------------------------------------- |
|||
subroutine wrtpos (ln, cn) |
|||
implicit none |
|||
integer ln, cn |
|||
write (*, 1000) ln, cn |
|||
1000 format ('At line ', I5, ', column ' I5) |
|||
end |
|||
#--------------------------------------------------------------------- |
|||
subroutine utcmnt (ln, cn) |
|||
implicit none |
|||
integer ln, cn |
|||
call wrtpos (ln, cn) |
|||
write (*, '(''Unterminated comment'')') |
|||
stop |
|||
end |
|||
subroutine skpcmt (line, linno, colno, pushbk, npshbk, ln, cn) |
|||
# Skip to the end of a comment. |
|||
implicit none |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer ln, cn # Line and column of start of comment. |
|||
integer chr(CHRSZ) |
|||
logical done |
|||
done = .false. |
|||
while (!done) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
if (chr(ICHRCD) == ichar ('*')) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
if (chr(ICHRCD) == ichar ('/')) |
|||
done = .true. |
|||
else if (chr(ICHRCD) == EOF) |
|||
call utcmnt (ln, cn) |
|||
} |
|||
else if (chr(ICHRCD) == EOF) |
|||
call utcmnt (ln, cn) |
|||
} |
|||
end |
|||
subroutine skpspc (line, linno, colno, pushbk, npshbk) |
|||
# Skip spaces and comments. |
|||
implicit none |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
logical isspc |
|||
integer chr(CHRSZ) |
|||
integer chr1(CHRSZ) |
|||
integer ln, cn |
|||
logical done |
|||
done = .false. |
|||
while (!done) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
if (!isspc (chr(ICHRCD))) |
|||
{ |
|||
if (chr(ICHRCD) != ichar ('/')) |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr) |
|||
done = .true. |
|||
} |
|||
else |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
if (chr1(ICHRCD) != ichar ('*')) |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr1) |
|||
call pshchr (pushbk, npshbk, chr) |
|||
done = .true. |
|||
} |
|||
else |
|||
{ |
|||
ln = chr(ILINNO) |
|||
cn = chr(ICOLNO) |
|||
call skpcmt (line, linno, colno, pushbk, npshbk, _ |
|||
ln, cn) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
end |
|||
#--------------------------------------------------------------------- |
|||
subroutine rwdlkp (strngs, istrng, src, i0, n0, ln, cn, tok) |
|||
# Reserved word lookup |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character src(*) # The source string. |
|||
integer i0, n0 # Index and length of the substring. |
|||
integer ln, cn # Line and column number |
|||
# to associate with the token. |
|||
integer tok(TOKSZ) # The output token. |
|||
integer tokno |
|||
integer i, n |
|||
tokno = TKID |
|||
if (n0 == 2) |
|||
{ |
|||
if (src(i0) == 'i' && src(i0 + 1) == 'f') |
|||
tokno = TKIF |
|||
} |
|||
else if (n0 == 4) |
|||
{ |
|||
if (src(i0) == 'e' && src(i0 + 1) == 'l' _ |
|||
&& src(i0 + 2) == 's' && src(i0 + 3) == 'e') |
|||
tokno = TKELSE |
|||
else if (src(i0) == 'p' && src(i0 + 1) == 'u' _ |
|||
&& src(i0 + 2) == 't' && src(i0 + 3) == 'c') |
|||
tokno = TKPUTC |
|||
} |
|||
else if (n0 == 5) |
|||
{ |
|||
if (src(i0) == 'p' && src(i0 + 1) == 'r' _ |
|||
&& src(i0 + 2) == 'i' && src(i0 + 3) == 'n' _ |
|||
&& src(i0 + 4) == 't') |
|||
tokno = TKPRNT |
|||
else if (src(i0) == 'w' && src(i0 + 1) == 'h' _ |
|||
&& src(i0 + 2) == 'i' && src(i0 + 3) == 'l' _ |
|||
&& src(i0 + 4) == 'e') |
|||
tokno = TKWHIL |
|||
} |
|||
i = 0 |
|||
n = 0 |
|||
if (tokno == TKID) |
|||
call addstr (strngs, istrng, src, i0, n0, i, n) |
|||
tok(ITOKNO) = tokno |
|||
tok(IARGIX) = i |
|||
tok(IARGLN) = n |
|||
tok(ILINNO) = ln |
|||
tok(ICOLNO) = cn |
|||
end |
|||
subroutine scnwrd (line, linno, colno, pushbk, npshbk, ln, cn, buf, n) |
|||
# Scan characters that may represent an identifier, reserved word, |
|||
# or integer literal. |
|||
implicit none |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer ln, cn # Line and column number of the start. |
|||
character buf(LINESZ) # The output buffer. |
|||
integer n # The length of the string collected. |
|||
logical isid1 |
|||
integer chr(CHRSZ) |
|||
n = 0 |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
ln = chr(ILINNO) |
|||
cn = chr(ICOLNO) |
|||
while (isid1 (chr(ICHRCD))) |
|||
{ |
|||
n = n + 1 |
|||
buf(n) = char (chr(ICHRCD)) |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
} |
|||
call pshchr (pushbk, npshbk, chr) |
|||
end |
|||
subroutine scnidr (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
# Scan an identifier or reserved word. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer ln, cn # Line and column number of the start. |
|||
integer tok(TOKSZ) # The output token. |
|||
character buf(LINESZ) |
|||
integer n |
|||
call scnwrd (line, linno, colno, pushbk, npshbk, ln, cn, buf, n) |
|||
call rwdlkp (strngs, istrng, buf, 1, n, ln, cn, tok) |
|||
end |
|||
subroutine scnint (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
# Scan a positive integer literal. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer ln, cn # Line and column number of the start. |
|||
integer tok(TOKSZ) # The output token. |
|||
logical isdgt |
|||
character buf(LINESZ) |
|||
integer n0, n |
|||
integer i, j, k |
|||
character*80 fmt |
|||
call scnwrd (line, linno, colno, pushbk, npshbk, ln, cn, buf, n0) |
|||
for (j = 1; j <= n0; j = j + 1) |
|||
if (!isdgt (ichar (buf(j)))) |
|||
{ |
|||
call wrtpos (ln, cn) |
|||
write (fmt, 1000) n0 |
|||
1000 format ('(''Not a legal word: "''', I10, 'A, ''"'')') |
|||
write (*, fmt) (buf(k), k = 1, n0) |
|||
stop |
|||
} |
|||
call addstr (strngs, istrng, buf, 1, n0, i, n) |
|||
tok(ITOKNO) = TKINT |
|||
tok(IARGIX) = i |
|||
tok(IARGLN) = n |
|||
tok(ILINNO) = ln |
|||
tok(ICOLNO) = cn |
|||
end |
|||
subroutine utclit (ln, cn) |
|||
implicit none |
|||
integer ln, cn |
|||
call wrtpos (ln, cn) |
|||
write (*, '(''Unterminated character literal'')') |
|||
stop |
|||
end |
|||
subroutine scnch1 (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
# Scan a character literal, without yet checking that the literal |
|||
# ends correctly. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer tok(TOKSZ) # The output token. |
|||
integer trimlf |
|||
integer bufsz |
|||
parameter (bufsz = 40) |
|||
integer chr(CHRSZ) |
|||
integer chr1(CHRSZ) |
|||
integer chr2(CHRSZ) |
|||
integer ln, cn |
|||
character buf(bufsz) |
|||
integer i, j, n |
|||
# Refetch the opening quote. |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
ln = chr(ILINNO) |
|||
cn = chr(ICOLNO) |
|||
tok(ITOKNO) = TKINT |
|||
tok(ILINNO) = ln |
|||
tok(ICOLNO) = cn |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
if (chr1(ICHRCD) == EOF) |
|||
call utclit (ln, cn) |
|||
if (chr1(ICHRCD) == BACKSL) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr2) |
|||
if (chr2(ICHRCD) == EOF) |
|||
call utclit (ln, cn) |
|||
else if (chr2(ICHRCD) == ichar ('n')) |
|||
{ |
|||
tok(IARGIX) = LOC10 # "10" = code for Unix newline |
|||
tok(IARGLN) = 2 |
|||
} |
|||
else if (chr2(ICHRCD) == BACKSL) |
|||
{ |
|||
tok(IARGIX) = LOC92 # "92" = code for backslash |
|||
tok(IARGLN) = 2 |
|||
} |
|||
else |
|||
{ |
|||
call wrtpos (ln, cn) |
|||
write (*, '(''Unsupported escape: '', 1A)') _ |
|||
char (chr2(ICHRCD)) |
|||
stop |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
# Character codes are non-negative, so we can use intstr. |
|||
call intstr (buf, 1, bufsz, chr1(ICHRCD)) |
|||
j = trimlf (buf, bufsz) |
|||
call addstr (strngs, istrng, buf, j, bufsz - (j - 1), i, n) |
|||
tok(IARGIX) = i |
|||
tok(IARGLN) = n |
|||
} |
|||
end |
|||
subroutine scnch (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
# Scan a character literal. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer tok(TOKSZ) # The output token. |
|||
integer ln, cn |
|||
integer chr(CHRSZ) |
|||
call getpos (line, linno, colno, pushbk, npshbk, ln, cn) |
|||
call scnch1 (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
if (chr(ICHRCD) != ichar ('''')) |
|||
{ |
|||
while (.true.) |
|||
{ |
|||
if (chr(ICHRCD) == EOF) |
|||
{ |
|||
call utclit (ln, cn) |
|||
stop |
|||
} |
|||
else if (chr(ICHRCD) == ichar ('''')) |
|||
{ |
|||
call wrtpos (ln, cn) |
|||
write (*, '(''Unsupported multicharacter literal'')') |
|||
stop |
|||
} |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
} |
|||
} |
|||
end |
|||
subroutine scnstr (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
# Scan a string literal. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer tok(TOKSZ) # The output token. |
|||
integer ln, cn |
|||
integer chr1(CHRSZ) |
|||
integer chr2(CHRSZ) |
|||
character buf(LINESZ + 10) # Enough space, with some room to spare. |
|||
integer n0 |
|||
integer i, n |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
ln = chr1(ILINNO) |
|||
cn = chr1(ICOLNO) |
|||
tok(ITOKNO) = TKSTR |
|||
tok(ILINNO) = ln |
|||
tok(ICOLNO) = cn |
|||
n0 = 1 |
|||
buf(n0) = '"' |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
while (chr1(ICHRCD) != ichar ('"')) |
|||
{ |
|||
# Our input method always puts a NEWLIN before EOF, and so this |
|||
# test is redundant, unless someone changes the input method. |
|||
if (chr1(ICHRCD) == EOF || chr1(ICHRCD) == NEWLIN) |
|||
{ |
|||
call wrtpos (ln, cn) |
|||
write (*, '(''Unterminated string literal'')') |
|||
stop |
|||
} |
|||
if (chr1(ICHRCD) == BACKSL) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr2) |
|||
if (chr2(ICHRCD) == ichar ('n')) |
|||
{ |
|||
n0 = n0 + 1 |
|||
buf(n0) = char (BACKSL) |
|||
n0 = n0 + 1 |
|||
buf(n0) = 'n' |
|||
} |
|||
else if (chr2(ICHRCD) == BACKSL) |
|||
{ |
|||
n0 = n0 + 1 |
|||
buf(n0) = char (BACKSL) |
|||
n0 = n0 + 1 |
|||
buf(n0) = char (BACKSL) |
|||
} |
|||
else |
|||
{ |
|||
call wrtpos (chr1(ILINNO), chr1(ICOLNO)) |
|||
write (*, '(''Unsupported escape sequence'')') |
|||
stop |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
n0 = n0 + 1 |
|||
buf(n0) = char (chr1(ICHRCD)) |
|||
} |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
} |
|||
n0 = n0 + 1 |
|||
buf(n0) = '"' |
|||
call addstr (strngs, istrng, buf, 1, n0, i, n) |
|||
tok(IARGIX) = i |
|||
tok(IARGLN) = n |
|||
end |
|||
subroutine unxchr (chr) |
|||
implicit none |
|||
integer chr(CHRSZ) |
|||
call wrtpos (chr(ILINNO), chr(ICOLNO)) |
|||
write (*, 1000) char (chr(ICHRCD)) |
|||
1000 format ('Unexpected character ''', A1, '''') |
|||
stop |
|||
end |
|||
subroutine scntok (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
# Scan a token. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer tok(TOKSZ) # The output token. |
|||
logical isdgt |
|||
logical isid0 |
|||
integer chr(CHRSZ) |
|||
integer chr1(CHRSZ) |
|||
integer ln, cn |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
ln = chr(ILINNO) |
|||
cn = chr(ICOLNO) |
|||
tok(ILINNO) = ln |
|||
tok(ICOLNO) = cn |
|||
tok(IARGIX) = 0 |
|||
tok(IARGLN) = 0 |
|||
if (chr(ICHRCD) == ichar (',')) |
|||
tok(ITOKNO) = TKCMMA |
|||
else if (chr(ICHRCD) == ichar (';')) |
|||
tok(ITOKNO) = TKSEMI |
|||
else if (chr(ICHRCD) == ichar ('(')) |
|||
tok(ITOKNO) = TKLPAR |
|||
else if (chr(ICHRCD) == ichar (')')) |
|||
tok(ITOKNO) = TKRPAR |
|||
else if (chr(ICHRCD) == ichar ('{')) |
|||
tok(ITOKNO) = TKLBRC |
|||
else if (chr(ICHRCD) == ichar ('}')) |
|||
tok(ITOKNO) = TKRBRC |
|||
else if (chr(ICHRCD) == ichar ('*')) |
|||
tok(ITOKNO) = TKMUL |
|||
else if (chr(ICHRCD) == ichar ('/')) |
|||
tok(ITOKNO) = TKDIV |
|||
else if (chr(ICHRCD) == ichar ('%')) |
|||
tok(ITOKNO) = TKMOD |
|||
else if (chr(ICHRCD) == ichar ('+')) |
|||
tok(ITOKNO) = TKADD |
|||
else if (chr(ICHRCD) == ichar ('-')) |
|||
tok(ITOKNO) = TKSUB |
|||
else if (chr(ICHRCD) == ichar ('<')) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
if (chr1(ICHRCD) == ichar ('=')) |
|||
tok(ITOKNO) = TKLE |
|||
else |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr1) |
|||
tok(ITOKNO) = TKLT |
|||
} |
|||
} |
|||
else if (chr(ICHRCD) == ichar ('>')) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
if (chr1(ICHRCD) == ichar ('=')) |
|||
tok(ITOKNO) = TKGE |
|||
else |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr1) |
|||
tok(ITOKNO) = TKGT |
|||
} |
|||
} |
|||
else if (chr(ICHRCD) == ichar ('=')) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
if (chr1(ICHRCD) == ichar ('=')) |
|||
tok(ITOKNO) = TKEQ |
|||
else |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr1) |
|||
tok(ITOKNO) = TKASGN |
|||
} |
|||
} |
|||
else if (chr(ICHRCD) == ichar ('!')) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
if (chr1(ICHRCD) == ichar ('=')) |
|||
tok(ITOKNO) = TKNE |
|||
else |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr1) |
|||
tok(ITOKNO) = TKNOT |
|||
} |
|||
} |
|||
else if (chr(ICHRCD) == ichar ('&')) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
if (chr1(ICHRCD) == ichar ('&')) |
|||
tok(ITOKNO) = TKAND |
|||
else |
|||
call unxchr (chr) |
|||
} |
|||
else if (chr(ICHRCD) == ichar ('|')) |
|||
{ |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr1) |
|||
if (chr1(ICHRCD) == ichar ('|')) |
|||
tok(ITOKNO) = TKOR |
|||
else |
|||
call unxchr (chr) |
|||
} |
|||
else if (chr(ICHRCD) == ichar ('"')) |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr) |
|||
call scnstr (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
} |
|||
else if (chr(ICHRCD) == ichar ('''')) |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr) |
|||
call scnch (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
} |
|||
else if (isdgt (chr(ICHRCD))) |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr) |
|||
call scnint (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
} |
|||
else if (isid0 (chr(ICHRCD))) |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr) |
|||
call scnidr (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
} |
|||
else |
|||
call unxchr (chr) |
|||
end |
|||
subroutine scntxt (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk) |
|||
# Scan the text and print the token stream. |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer chr(CHRSZ) |
|||
integer tok(TOKSZ) |
|||
chr(ICHRCD) = ichar ('x') |
|||
while (chr(ICHRCD) != EOF) |
|||
{ |
|||
call skpspc (line, linno, colno, pushbk, npshbk) |
|||
call getchr (line, linno, colno, pushbk, npshbk, chr) |
|||
if (chr(ICHRCD) != EOF) |
|||
{ |
|||
call pshchr (pushbk, npshbk, chr) |
|||
call scntok (strngs, istrng, _ |
|||
line, linno, colno, pushbk, npshbk, _ |
|||
tok) |
|||
call prttok (strngs, tok) |
|||
} |
|||
} |
|||
tok(ITOKNO) = TKEOI |
|||
tok(ILINNO) = chr(ILINNO) |
|||
tok(ICOLNO) = chr(ICOLNO) |
|||
tok(IARGIX) = 0 |
|||
tok(IARGLN) = 0 |
|||
call prttok (strngs, tok) |
|||
end |
|||
#--------------------------------------------------------------------- |
|||
program lex |
|||
implicit none |
|||
character strngs(STRNSZ) # String pool. |
|||
integer istrng # String pool's next slot. |
|||
character line(LINESZ) # Input buffer. |
|||
integer linno, colno # Current line and column numbers. |
|||
integer pushbk(CHRSZ, PSHBSZ) # Pushback buffer. |
|||
integer npshbk # Number of characters pushed back. |
|||
integer i, n |
|||
istrng = 1 |
|||
# Locate "10" (newline) at 1 in the string pool. |
|||
line(1) = '1' |
|||
line(2) = '0' |
|||
call addstr (strngs, istrng, line, 1, 2, i, n) |
|||
if (i != 1 && n != 2) |
|||
{ |
|||
write (*, '(''internal error'')') |
|||
stop |
|||
} |
|||
# Locate "92" (backslash) at 3 in the string pool. |
|||
line(1) = '9' |
|||
line(2) = '2' |
|||
call addstr (strngs, istrng, line, 1, 2, i, n) |
|||
if (i != 3 && n != 2) |
|||
{ |
|||
write (*, '(''internal error'')') |
|||
stop |
|||
} |
|||
linno = 0 |
|||
colno = LINESZ + 1 # This will trigger a READ. |
|||
npshbk = 0 |
|||
call scntxt (strngs, istrng, line, linno, colno, pushbk, npshbk) |
|||
end |
|||
######################################################################</lang> |
|||
=={{header|Scala}}== |
=={{header|Scala}}== |