文書整形 -- 指令の解析 ― 2016年12月05日 21:03
指令の解析は容易であり、comtyp()で行う。メインルーチンから呼び出される comand()から、最初にcomtyp()が呼び出される。comand()は、comtyp()の返す値に従い、 必要な処理を行っていく。comand()は以下の通りである。
RATFORでは、
# comand.r4 -- perform formatting command subroutine comand( buf ) character buf(MAXLINE) integer comtyp, getval integer ct, spval, val integer argtyp include cpage.ri include cparam.ri ct = comtyp(buf) if (ct == UNKOWN) # igore unknown commands return val = getval(buf,argtyp) if (ct == FI) { call brk fill = YES } else if (ct == NF) { call brk fill = NOC } else if (ct == BR) call brk else if (ct == LS) call set(lsval,val,argtyp,1,1,HUGE) else if (ct == HE) call gettl(buf,header) else if (ct == FO) call gettl(buf,footer) else if (ct == SP) { call set(spval,val,argtyp,1,0,HUGE) call space(spval) } else if (ct == BP) { if (lineno > 0) call space(HUGE) call set(curpage,val,argtyp,curpage+1,-HUGE,HUGE) newpag = curpag } else if (ct == PL) { call set(plval,val,argtyp,PAGELEN,m1val+m2val+m3val+m4val+1,HUGE) bottom = plval - m3val - m4val } else if (ct == IN) { call set(inval,val,argtyp,0,0,rmval-1) tival = inval } else if (ct == RM) call set(rmval,val,argtyp,PAGEWIDTH,tival+1,HUDGE) else if (ct == TI) { call brk call set(tival,val,argtyp,0,0,rmval-1) } else if (ct == CE) { call brk call set(ceval,val,argtyp,1,0,HUGE) } else if (ct .eq. 14) then ! UL(14) call set(ulval,val,argtyp,1,0,HUGE) return end
WATCOM fortran 77では、
c comand.f -- perform formatting command subroutine comand( buf ) integer*1 buf(82) ! MAXLINE(82) integer comtyp, getval integer ct, spval, val integer*1 argtyp include cpage.fi include cparam.fi ct = comtyp(buf) if (ct .eq. 0) then ! UNKOWN(0) return end if val = getval(buf,argtyp) if (ct .eq. 4) then ! FI(4) call brk fill = 1 ! YES(1) else if (ct .eq. 9) then ! NF(9) call brk fill = 0 ! NOC(0) else if (ct .eq. 2) then ! BR(2) call brk else if (ct .eq. 8) then ! LS(8) call set(lsval,val,argtyp,1,1,1000) ! HUGE(1000) else if (ct .eq. 6) then ! HE(6) call gettl(buf,header) else if (ct .eq. 5) then ! FO(5) call gettl(buf,footer) else if (ct .eq. 12) then ! SP(12) call set(spval,val,argtyp,1,0,1000) ! HUGE(1000) call space(spval) else if (ct .eq. 1) then ! BP(1) if (lineno .gt. 0) then call space(1000) ! HUGE(1000) end if call set(curpage,val,argtyp,curpage+1,-1000,1000) ! HUGE(1000) newpag = curpag else if (ct .eq. 10) then ! PL(10) call set(plval,val,argtyp,66, ! PAGELEN(66) 1 m1val+m2val+m3val+m4val+1,1000) ! HUGE(1000) bottom = plval - m3val - m4val else if (ct .eq. 7) then ! IN(7) call set(inval,val,argtyp,0,0,rmval-1) tival = inval else if (ct .eq. 11) then ! RM(11) call set(rmval,val,argtyp,60,tival+1,1000) ! PAGEWIDTH(60) HUGE(1000) else if (ct .eq. 13) then ! TI(13) call brk call set(tival,val,argtyp,0,0,rmval-1) else if (ct .eq. 3) then ! CE(3) call brk call set(ceval,val,argtyp,1,0,1000) ! HUGE(1000) else if (ct .eq. 14) then ! UL(14) call set(ulval,val,argtyp,1,0,1000) ! HUGE(1000) end if return end
実際の指令の解析は、comtyp()が行う。
RATFOR版は、以下の通り。
c comtyp.r4 -- decode command type integer function comtyp(buf) character buf(MAXLINE) if (buf(2) == LETB & buf(3) == LETP) comtyp = BP else if (buf(2) == LETB & buf(3) == LETR) comtyp = BR else if (buf(2) == LETC & buf(3) == LETE) comtyp = CE else if (buf(2) == LETF & buf(3) == LETI) comtyp = FI else if (buf(2) == LETF & buf(3) == LETO) comtyp = FO else if (buf(2) == LETH & buf(3) == LETE) comtyp = HE else if (buf(2) == LETI & buf(3) == LETN) comtyp = IN else if (buf(2) == LETL & buf(3) == LETS) comtyp = LS else if (buf(2) == LETN & buf(3) == LETF) comtyp = NF else if (buf(2) == LETP & buf(3) == LETL) comtyp = PL else if (buf(2) == LETR & buf(3) == LETM) comtyp = RM else if (buf(2) == LETS & buf(3) == LETP) comtyp = SP else if (buf(2) == LETT & buf(3) == LETI) comtyp = TI else if (buf(2) == LETU & buf(3) == LETL) comtyp = UL else comtyp = UNKOWN end if return end
WATCOM fortran77版は、以下の通り。
c comtyp.for -- decode command type integer function comtyp(buf) integer*1 buf(82) ! MAXLINE(82) if ((buf(2) .eq. 98) .and. (buf(3) .eq. 112)) then ! LETB('b',98) LETP('p',112) comtyp = 1 ! BP(1) else if ((buf(2) .eq. 98) .and. (buf(3) .eq. 114)) then ! LETB('b',98) LETR('r',114) comtyp = 2 ! BR(2) else if ((buf(2) .eq. 99) .and. (buf(3) .eq. 101)) then ! LETC('c',99) LETE('r',101) comtyp = 3 ! CE(3) else if ((buf(2) .eq. 102) .and. (buf(3) .eq. 105)) then ! LETF('f',102) LETI('i',105) comtyp = 4 ! FI(4) else if ((buf(2) .eq. 102) .and. (buf(3) .eq. 111)) then ! LETF('f',102) LETO('o',111) comtyp = 5 ! FO(5) else if ((buf(2) .eq. 104) .and. (buf(3) .eq. 101)) then ! LETH('h',104) LETE('e',101) comtyp = 6 ! HE(6) else if ((buf(2) .eq. 105) .and. (buf(3) .eq. 110)) then ! LETI('i',105) LETN('n',110) comtyp = 7 ! IN(7) else if ((buf(2) .eq. 108) .and. (buf(3) .eq. 115)) then ! LETL('l',108) LETS('n',115) comtyp = 8 ! LS(8) else if ((buf(2) .eq. 110) .and. (buf(3) .eq. 102)) then ! LETN('n',110) LETF('f',102) comtyp = 9 ! NF(9) else if ((buf(2) .eq. 112) .and. (buf(3) .eq. 108)) then ! LETP('n',112) LETL('l',108) comtyp = 10 ! PL(10) else if ((buf(2) .eq. 114) .and. (buf(3) .eq. 109)) then ! LETR('r',114) LETM('m',109) comtyp = 11 ! RM(11) else if ((buf(2) .eq. 115) .and. (buf(3) .eq. 112)) then ! LETS('s',115) LETP('p',112) comtyp = 12 ! SP(12) else if ((buf(2) .eq. 116) .and. (buf(3) .eq. 105)) then ! LETT('t',116) LETI('i',105) comtyp = 13 ! TI(13) else if ((buf(2) .eq. 117) .and. (buf(3) .eq. 108)) then ! LETU('u',117) LETL('l',108) comtyp = 14 ! UL(14) else comtyp = 0 ! UNKOWN(0) end if return end
指令の引数は、getval()で取得する。取得した値は、set()で設定する。
getval()のRATFOR版は、以下の通り。
# getval.r4 - evaluate optional numeric argument integer function getval(buf,argtyp) character buf(MAXLINE) integer ctoi integer argtyp, i i = 1 # skip command name while (buf(i) != BLANK & buf(i) != TAB & buf(i) != NEWLINW) i = i + 1 call skipbl(buf,i) # find argument argtyp = buf(i) if (argtyp == PLUS | argtyp == MINUS) i = i + 1 getval = ctoi(buf,i) return end
WATCOM fortran版は、以下の通り。
c getval.for - evaluate optional numeric argument integer function getval(buf,argtyp) integer*1 buf(82) ! MAXLINE(82) integer ctoi integer argtyp, i i = 1 ! skip command name while ((buf(i) .ne. 32) ! BLANK(32) 1 .and. (buf(i) .ne. 9) ! TAB(9) 2 .and. (buf(i) .ne. 10)) do ! NEWLINE(10) i = i + 1 end while call skipbl(buf,i) ! find argument argtyp = buf(i) if ((argtyp .eq. 43) .or. (argtyp .eq. 45)) then ! PLUS('+',43) MINUS('-',45) i = i + 1 end if getval = ctoi(buf,i) return end
set()のRATFOR版は、以下の通り。
# set.r4 -- set parameter and check range subroutine set( param, val, argtyp, defval, minval, maxval ) integer param, val, defval, minval, maxval character argtyp integer max,min if (argtyp == NEWLINE) param = defval else if (argtyp == PLUS) param = param + val else if (argtyp == MINUS) param = param - val else param = val param = min( param, maxval ) param = max( param, minval ) return end
WATCOM fortran版は、以下の通り。
c set.for -- set parameter and check range subroutine set( param, val, argtyp, defval, minval, maxval ) integer param, val, defval, minval, maxval integer*1 argtyp integer max,min if (argtyp .eq. 10) then ! defaulted NEWLINE(10) param = defval else if (argtyp .eq. 43) then ! relative + PLUS('+',43) param = param + val else if (argtyp .eq. 45) then ! relative - NIMUS('-',45) param = param - val else param = val endif param = min( param, maxval ) param = max( param, minval ) return end
文書整形 -- テキストの書き出し ― 2016年12月10日 18:40
指令以外の行は、テキストである。これを書き出すルーチンtext()の 臨時第一版を示す。この版は下請けルーチンput()を呼び出すだけである。
RATFORでは、
# text.r4 -- process text lines (interim version 1) subroutine text(inbuf) character inbuf(INSIZE) call put(inbuf) return end
WATCOM fortran 77では、
c text.f -- process text lines (interim version 1) subroutine text(inbuf) integer*1 inbuf(82) ! INSIZE(82) call put(inbuf) return end
下請けルーチンput()では、ページのレイアウトを考慮した出力が作り出される。
RATFOR版は、以下の通り。
# put.r4 -- put out line with proper spacing and indenting subroutine put(buf) character buf(MAXLINE) integer min integer i include cpage.ri include cparam.ri if (lineno == 0 | lineno > bottom) call phead for (i = 1; i <= tival; i = i + 1) # indenting call putc(BLANK) tival = inval call putlin(buf,STDOUT) call skip(min(lsval-1,bottom-lineno)) lineno = lineno + lsval if (lineno > bottom) call pfoot return end
WATCOM fortran77版は、以下の通り。
c put.f -- put out line with proper spacing and indenting subroutine put(buf) integer*1 buf(82) ! MAXLINE(82) integer min integer i include cpage.fi include cparam.fi if ((lineno .eq. 0) .or. (lineno .gt. bottom)) then call phead end if i = 1 ! indenting while (i .le. tival) do call putc(32) ! BLANK(32) i = i + 1 end while tival = inval call putlin(buf,6) ! STDOUT(6) call skip(min(lsval-1,bottom-lineno)) lineno = lineno + lsval if (lineno .gt. bottom) then call pfoot end if return end
ページ見出し、ヘッダーとフッターは、phead()、pfoot()で書き出す。 put()は、これらを適当な位置で書き出すよう制御する。
phead()のRATFOR版は、以下の通り。
# phead.r4 -- put out page header subroutine phead include cpage.ri curpag = newpag newpag = newpag + 1 if (m1val > 0) { call skip(m1val - 1) call puttl(header,curpag) } call skip(m2val) lineno = m1val + m2val + 1 return end
WATCOM fortran 77版は、以下の通り。
c phead.f -- put out page header subroutine phead include cpage.fi curpag = newpag newpag = newpag + 1 if (m1val .gt. 0) then call skip(m1val-1) call puttl(header,curpag) end if call skip(m2val) lineno = m1val + m2val + 1 return end
pfoot()のRATFOR版は、以下の通り。
# pfoot.r4 -- put out page footer subroutine pfoot include cpage.ri call skip(m3val) if (m4val > 0) { call puttl(footer,curpag) call skip(m4val - 1) } return end
WATCOM fortran 77版は、以下の通り。
c pfoot.f -- put out page footer subroutine pfoot include cpage.fi call skip(m3val) if (m4val .gt. 0) then call puttl(footer,curpag) call skip(m4val - 1) endif return end
phead()、pfoot()とも、ページ見出しの書き出しはputtl()を使用する。 puttl()は、書き出す内容にPAGEMUN記号("#")が含まれていた場合、 その場所にページ番号を入れ込む。
puttl()のRATFOR版は、以下の通り。
# puttl.r4 -- put title line with optional page number subroutine puttl(buf,pageno) character buf(MAXLINE) integer pageno integer i for (i = 1; buf(i) != EOS; i = i + 1) if (buf(i) == PAGENUM) call putdec(pageno,1) else call putc(buf(i)) return end
WATCOM fortran 77版は、以下の通り。
c puttl.for -- put title line with optional page number subroutine puttl(buf,pageno) integer*1 buf(82) ! MAXLINE(82) integer pageno integer i i = 1 while (buf(i) .ne. -2) do ! EOS(-2) if (buf(i) .eq. 35) then ! PAGENUM('#',35) call putdec(pageno,1) else call putc(buf(i)) end if i = i + 1 end while return end
ページ見出しは、gettl()でページ見出し用のバッファーにセットする。
gettl()のRATFOR版は、以下の通り。
# gettl.r4 -- copy title from buf to ttl subroutine gettl(buf,ttl) character buf(MAXLINE),ttl(MAXLINE) integer i i = 1 # skip command name while ( buf(i) != BLANK & buf(i) != TAB & buf(i) != NEWLINE ) i = i + 1 call skipbl(buf,i) # find argument if (buf(i) == SQUORT | buf(i) == DQUORT) # strip quorte if found i = i + 1 call scopy(buf, i, ttl, 1) return end
WATCOM fortran 77版は、以下の通り。
c gettl.for -- copy title from buf to ttl subroutine gettl(buf,ttl) integer*1 buf(82),ttl(82) ! MAXLINE(82) MAXLINE(82) integer i i = 1 ! skip command name while ((buf(i) .ne. 32) ! BLANK(32) 1 .and. (buf(i) .ne. 9) ! TAB(9) 2 .and. (buf(i) .ne. 10)) do ! NEWLINE(10) i = i + 1 end while call skipbl(buf,i) ! find argument if ((buf(i) .eq. 39) 1 .or. (buf(i) .eq. 34)) then ! strip quorte if found SQUOTE(''',39) DQUOTE('"',34) i = i + 1 end if call scopy(buf,i,ttl,1) return end
".sp"指令や".bp"指令は、space()で空行を出力しページレイアウトを 調整する。
space()のRATFOR版は、以下の通り。
# space.r4 -- space n lines or to bottom of page subroutine space(n) integer n integer min include cpage.ri call brk if (lineno > bottom) return if (lineno == 0) call phead call skip(min(n, bottom + 1 - lineno)) lineno = lineno + n if (lineno > bottom) call pfoot return end
WATCOM fortran 77版は、以下の通り。
c space.f -- space n lines or to bottom of page subroutine space(n) integer n integer min include cpage.fi call brk if (lineno .gt. bottom) then return end if if (lineno .eq. 0) then call phead end if call skip(min(n,bottom+1-lineno)) lineno = lineno + n if (lineno .gt. bottom) then call pfoot end if return end
文書整形 -- 出力の右揃えなど ― 2016年12月14日 18:13
現在の出力は、行の右端が不揃いになる。これを解消するのに、 putwrd()を修正する。この中のspread()は、語の間の空白を調整し一行の中に、語を 割り付ける。
RATFORでは
# putwrd.r4 -- put a word in outbuf; include margin justification subroutine putwrd(wrdbuf) character wrdbuf(INSIZE) integer length,width integer last,llval,nextra,w include cout.fi include cparam.fi w = width(wrdbuf) last = length(wrdbuf) + outp + 1 ! new end of outbuf llval = rmval - tival if ((outp > 0) & (outw+w > llval | last >= MAXOUT)) { # too big last = last - outp # remember end of wrdbuf nextra = llval - outw + 1 call spread(outbuf,outp,nextra,outwds) if ((nextra > 0) & (outwds > 1)) outp = outp + nextra call brk # flush previous line } call scopy(wrdbuf,1,outbuf,outp+1) outp = last outbuf(outp) = BLANK # blank between words outw = outw + w + 1 # 1 for blank outwds = outwds + 1 return end
WATCOM fortran 77では、
c putwrd.f -- put a word in outbuf; include margin justification subroutine putwrd(wrdbuf) integer*1 wrdbuf(82) ! INSIZE(82) integer length,width integer last,llval,nextra,w include cout.fi include cparam.fi w = width(wrdbuf) last = length(wrdbuf) + outp + 1 ! new end of outbuf llval = rmval - tival if ((outp .gt. 0) .and. 1 ((outw+w .gt. llval) .or. (last .ge. 74))) then ! MAXOUT(74) too big last = last - outp ! remember end of wrdbuf nextra = llval - outw + 1 call spread(outbuf,outp,nextra,outwds) if ((nextra .gt.0) .and. (outwds .gt. 1)) then outp = outp + nextra end if call brk ! flush previous line end if call scopy(wrdbuf,1,outbuf,outp+1) outp = last outbuf(outp) = 32 ! BLANK(32) blank between words outw = outw + w + 1 ! 1 for blank outwds = outwds + 1 return end
spread()は、以下の通り
RATFORでは
# spread.r4 -- spread words to justify right margin subroutine spread(buf,outp,nextra,outwds) character buf(MAXOUT) integer outp,nextra,outwds integer min integer dir,i,j,nb,ne,nholes data dir/0/ if ((nextra <= 0) | (outwds <= 1)) return dir = 1 - dir # reverce previouse direction ne = nextra nholes = outwds - 1 i = outp - 1 j = min(MAXLINE - 2, i + ne) # leave room for NEWLINE, EOS while (i < j) { buf(j) = buf(i) if (buf(i) == BLANK) { if (dir == 0) nb = (ne - 1) / nholes + 1 else nb = ne / nholes ne = ne - nb nholes = nholes - 1 for ( ; nb > 0; nb = nb - 1) { j = j - 1 buf(j) = BLANK } } i = i - 1 j = j - 1 } return end
WATCOM fortran 77では、
c spread.for -- spread words to justify right margin subroutine spread(buf,outp,nextra,outwds) integer*1 buf(74) ! MAXOUT(74) integer outp,nextra,outwds integer min integer dir,i,j,nb,ne,nholes data dir/0/ if ((nextra .le. 0) .or. (outwds .le. 1)) then return end if dir = 1 - dir ! reverce previouse direction ne = nextra nholes = outwds - 1 i = outp - 1 j = min(74-2, i+ne) ! MAXOUT(74) -2 for leave room for NEWLINE, EOS while (i .lt. j) do buf(j) = buf(i) if (buf(i) .eq. 32) then ! BLANK(32) if (dir .eq. 0) then nb = (ne - 1) / nholes + 1 else nb = ne / nholes end if ne = ne - nb nholes = nholes - 1 while (nb .gt. 0) do j = j - 1 buf(j) = 32 ! BLANK(32) nb = nb - 1 end while end if i = i - 1 j = j - 1 end while return end
中央そろえは、center()で行う。実際は、一時字下げの値を調節する。
RATFORでは
# center.r4 -- center a line by setting tival subroutine center(buf) character buf(ARB) integer width,max include cparam.fi tival = max((rmval + tival - width(buf)) / 2, 0) return end
WATCOM fortran 77では、
c center.f -- center a line by setting tival subroutine center(buf) integer*1 buf(9999) ! ARB(9999) integer width,max include cparam.fi tival = max((rmval + tival - width(buf)) / 2, 0) return end
下線は、書き出し文字とBACKSPACE、UNDERLINEを組み合わせ作り出す。 実際は、underl()で書き出し文字列を作り出す。
RATFORでは
# underl.r4 -- underline a line subroutine underl(buf,tbuf,size) character buf(size),tbuf(size) integer size integer type integer i,j,t j = 1 for (i = 1; buf(i) != NEWLINE & j < size- 1; i = i + 1) { tbuf(j) = buf(i) j = j + 1 if (buf(i) != BLANK & buf(i) != TAB & buf(i) != BACKSPACE) { tbuf(j) = BACSPACE tbuf(j+1) = UNDERLINE j = j + 2 } } tbuf(j) = NEWLINE tbuf(j+1) = EOS call scopy(tbuf, 1, buf, 1) # copy it back to buf return end
WATCOM fortran 77では、
c underl.for -- underline a line subroutine underl(buf,tbuf,size) integer*1 buf(size),tbuf(size) integer size integer i,j,t j = 1 i = 1 while ((buf(i) .ne. 10) .and. (j .lt. size-1)) do ! NEWLINE(10) tbuf(j) = buf(i) j = j + 1 if ((buf(i) .ne. 32) ! BLANK(32) 1 .and. (buf(i) .ne. 9) ! TAB(9) 2 .and. (buf(i) .ne. 8)) then ! BACKSPACE(8) tbuf(j) = 8 ! BACKSPACE(8) tbuf(j+1) = 95 ! UNDERLINE(95) j = j + 2 end if i = i + 1 end while tbuf(j) = 10 ! NEWLINE(10) tbuf(j+1) = -2 ! EOS(-2) call scopy(tbuf,1,buf,1) ! copy it back to buf return end
ここまで出てきた新機能を追加するには、text()を修正する必要がある。 text()の最終版は、以下の通り。
RATFORでは
# text.r4 -- process text lines (final version) subroutine text(inbuf) character inbuf(INSIZE), wrdbuf(INSIZE) integer getword integer i include cparam.ri if (inbuf(1) == BLANK | inbuf(1) == NEWLINE) call leadbl(inpuf) # move left, set tival if (ulval > 0) { # underlining call underl(inbuf,wrdbuf,INSIZE) ulval = ulval - 1 } if (ceval > 0) { # centering call center(inbuf) call put(inbuf) ceval = ceval - 1 } else if (inbuf(1) == NEWLINE) # all blank line call put(inbuf) else if (fill == NO) # unfiled text call put(inbuf) else # filled text for (i = 1;getwrd(inbuf,i,wrdbuf)>0; ) call putwrd(wrdbuf) return end
WATCOM fortran 77では、
c text.f -- process text lines (final version) subroutine text(inbuf) integer*1 inbuf(82), wrdbuf(82) ! INSIZE(82) INSIZE(82) integer getwrd integer i include cparam.fi if (inbuf(1) .eq. 32 .or. inbuf(1) .eq. 10) then ! BLANK(32) NEWLINE(10) call leadbl(inpuf) ! move left, set tival end if if (ulval .gt. 0) then ! underlining call underl(inbuf,wrdbuf,INSIZE) ulval = ulval - 1 end if if (ceval .gt. 0) then ! centering call center(inbuf) call put(inbuf) ceval = ceval - 1 else if (inbuf(1) .eq. 10) then ! all blank line call put(inbuf) else if (fill .eq. 0) then ! unfiled text NO(0) call put(inbuf) else ! filled text i = 1 while (getwrd(inbuf,i,wrdbuf) .gt. 0 ) do call putwrd(wrdbuf) end while end if return end
マクロ処理 -- 文字列の置換版 ― 2016年12月31日 20:06
これまで紹介したRATFORのプログラムリストには、記号定数が ふんだんに使われてきた。記号定数は最終的には、定数に置換する必要がある。 これを行う事をマクロ展開という。また、それを行うプログラムをマクロプロセッサー という。このプログラムは、プリグラム中に書き込まれたマクロを展開し書き出す。
まずはじめに、文字列の置換版 -- define を紹介する。
defineでの、マクロの定義は次のようになる。
define(EOF,-1)
このように定義されたマクロは、ソースファイルに下記のように使われる。
define(EOF,-1) program copy # copy from STDIN to STDOUT call initfile while(getc(c) != EOF) call putc(c) stop end
これをマクロ展開すると、
program copy # copy from STDIN to STDOUT call initfile while(getc(c) != -1) call putc(c) stop end
このようなカンタンな場合から、マクロプロセッサーをはじめる。
マクロプロセッサーのあらすじは、次のようになるだろう。
while(gettok(綴り) != EOF) { 綴りの表を引く if (綴り == "define") 新しい綴りとその値を登録 else if (綴りが表にあった) 入力を綴りに対応する置き換え文字列に切り替える else 綴りをそのまま出力する
ここで、gettok()は以下の通り。
RATFOR版は、
# gettok.r4 -- get alphanumeric string non-alpha for define character function gettok(token,toksiz) integer toksiz character token(toksiz) character ngetc,type integer i for (i = 1; i < toksiz; i = i + 1) { gettok = type(ngetc(token(i))) if (gettok != LETTER) & (gettok != DIGIT) break } if (i >= toksiz) call error('token too long.') if (i > 1) { # some alpha was seen call putbak(token(i)) i = i - 1 gettok = ALPHA # else single character token token(i+1) = EOS return end
RATFOR版は、
c gettok.for -- get alphanumeric string or single non-alpha for define integer*1 function gettok(token,toksiz) integer toksiz integer*1 token(toksiz) integer*1 ngetc,type integer i i = 1 while (i .lt. toksiz) do gettok = type(ngetc(token(i))) if ((gettok .ne. 97) .and. ! ALPHA(97) 1 (gettok .ne. 48)) then ! DIGIT(48) exit end if i = i + 1 end while if (i .ge. toksiz) then call error('token too long.') end if if (i .gt. 1) then ! some alpha was seen call putbak(token(i)) i = i - 1 gettok = 97 ! ALPHA(97) ! else single character token end if token(i+1) = -2 ! EOS(-2) return end
gettok()では、綴り取り出すときに、先読みを行う。当然、先読みした分は、 元に戻す必要もある。これらの統一的に行うのに、ngetc()、putbak()を使う。
読みすぎた文字は、putbak()で元に戻す。putbak()は、ngetc()と共有の バッファーを持っている。このバッファーには、putbak()で戻された文字が 蓄えられる。ngetc()はこのバッファーに残りがあれば、そこから文字を取り出し、 さもなくば、getc()で文字を読み込む。
putbak()は、以下の通り。
RATFOR版は、
# putbak.r4 -- push character back onto input subroutine putbak(c) character c include cdefio.ri bp = bp + 1 if (bp > BUFSIZE) call error('too many character pushed back.') buf(bp) = c return end
WATCOM fortran 77版は、
c putbak.f -- push character back onto input subroutine putbak(c) integer*1 c include cdefio.fi bp = bp + 1 if (bp .gt. 1000) then ! BUFSIZE(1000) call error('too many character pushed back.') end if buf(bp) = c return end
putbak()、ngetc()共通のデータ領域cdefioは、以下の通り。
RATFOR版は、
# cdefio.ri common /cdefio/bp,buf(BUFSIZE) integer bp # next available character; init = 0 character buf # pushed back character
WATCOM fortran 77版は、
c cdefio.fi common /cdefio/bp,buf(1000) ! BUFSIZE(1000) integer bp ! next available character; init = 0 character buf ! pushed back character
文字列を入力に送り返すことは、多々あるわけでないが、putbak()を 複数回呼び出すことで、実現できる。pbstr()は、以下の通り。
RATFOR版は、
# pbstr.r4 -- push string back onto input subroutine pbstr(in) character in(MAXLINE) integer length integer i for (i = length( in ); i > 0; i = i - 1) call putbak(in(i)) return end
WATCOM fortran 77版は、
c pbstr.for -- push string back onto input subroutine pbstr(in) integer*1 in(82) ! MAXLINE(82) integer length integer i i = length( in ) while (i .gt. 0) do call putbak(in(i)) i = i - 1 end while return end
ngetc()は、以下の通り。
RATFOR版は、
# ngetc.r4 -- get a (possibly pushed back) character character function ngetc( c ) character c character getc include cdefio.ri if (bp > 0) c = buf(bp) else { bp = 1 buf(bp) = getc(c) } if (c != EOF) bp = bp - 1 ngetc = c return end
WATCOM fortran 77版は、
! ngetc.f -- get a (possibly pushed back) character integer*1 function ngetc( c ) integer*1 c integer*1 getc include cdefio.fi if (bp .gt. 0) then c = buf(bp) else bp = 1 buf(bp) = getc(c) end if if (c .ne. -1) then ! EOF(-1) bp = bp - 1 end if ngetc = c return end
cdefioの初期化は、initbuf()で行う。
RATFOR版は、
# initbuf.r4 subroutine initbuf include cdefio.ri bp = 0 buf(1) = EOS return end
WATCOM fortran 77版は、
c initbuf.f subroutine initbuf include cdefio.fi bp = 0 buf(1) = -2 ! EOS(-2) return end
defineのメインルーチンは、以下の通りである。
gettok()で 綴りを切り出す。gettok()がALPHA以外を返したら、マクロではないから、そのまま、 出力する。綴りの表は、lookup()を使って引く。表に載っていなかったら、それは、 そのまま出力する。表に載っていて、それがDEFTYPEであったら、新しいマクロを getdef()で取り出し。マクロ表にinstall()で登録する。 登録されているマクロ名であれば、置き換え文字列を 入力に送り返す。
RATFOR版は以下の通り。
# define.r4 -- simple string replacement macro processor program define integer gettok character defn(MAXDEF),t,token(MAXTOK) integer lookup string defnam "define" character deftyp(2) data deftyp(1)/DEFTYPE/,deftyp(2)/EOS/ call initfile call inittbl call initbuf call instal(defnam,deftyp) for(t = gettok(token,MAXTOK);t != EOF;t = gettok(token,MAXTOK)) if (t != ALPHA) # output non-alpha tokens call putlin(token,STDOUT) else if (lookup(token,defn) == NO) call putlin(token,STDOUT) else if (defn(1) == DEFTYPE) then # get definition call getdef(token,MAXTOK,defn,MAXTOK) call instal(token,defn) else call pbstr(defn) # push replacement end if end while stop end
WATCOM fortran 77版は以下の通り。
c define.f -- simple string replacement macro processor program define integer gettok integer*1 defn(82),t,token(82) ! MAXDEF(82) MAXTOK(82) integer lookup integer*1 defnam(7) character $defnam(7) equivalence (defnam,$defnam) data $defnam(1)/'d'/ data $defnam(2)/'e'/ data $defnam(3)/'f'/ data $defnam(4)/'i'/ data $defnam(5)/'n'/ data $defnam(6)/'e'/ data defnam(7)/-2/ ! EOS(-2) integer*1 deftyp(2) data deftyp(1)/-4/,deftyp(2)/-2/ ! DEFTYPE(-4) EOS(-2) call initfile call inittbl call initbuf call instal(defnam,deftyp) t = gettok(token,82) ! MAXTOK(82) while (t .ne. -1) do ! EOF(-1) if (t .ne. 97) then ! ALPHA(97) output non-alpha tokens call putlin(token,6) ! STDOUT(6) else if (lookup(token,defn) .eq. 0) then ! NO(0) and undefined call putlin(token,6) ! STDOUT(6) else if (defn(1) .eq. -4) then ! DEFTYPE(-4) get definition call getdef(token,82,defn,82) ! MAXTOK(82) MAXDEF(82) call instal(token,defn) else call pbstr(defn) ! push replacement end if t = gettok(token,82) ! MAXTOK(82) end while stop end
マクロを取り出すgetdef()は、以下の通り。
RATFOR版は以下の通り。
# getdef.r4 (for no argument) -- get name and definition subroutine getdef(token,toksiz,defn,defsiz) integer toksiz, defsiz character token(toksiz),defn(defsiz) character gettok,ngetc character c integer i,nlpar if (ngetc(c) != LPAREN) call error('missing left paren.') else if (gettok(token,toksiz) != ALPHA) call error('non-alphanumeric name.') else if (ngetc(c) != COMMA) call error('missing comma in DEFINE.') ! else got (name, nlpar = 0 for (i = 1;nlpar >= 0; i = i + 1) if (i > defsiz) call error('definition too long.') else if (ngetc(defn(i)) == EOF) call error('missing right paren.') else if (defn(i) == LPAREN) nlpar = nlpar + 1 else if (defn(i) == RPAREN nlpar = nlpar - 1 ! else normal character indefn(i) defn(i-1) = EOS return end
WATCOM fortran 77版は以下の通り。
c getdef.f (for no argument) -- get name and definition subroutine getdef(token,toksiz,defn,defsiz) integer toksiz, defsiz integer*1 token(toksiz),defn(defsiz) integer*1 gettok,ngetc integer*1 c integer i,nlpar if (ngetc(c) .ne. 40) then ! LPAREN(40) call error('missing left paren.') else if (gettok(token,toksiz) .ne. 97) then ! ALPHA(97) call error('non-alphanumeric name.') els eif (ngetc(c) .ne. 44) then ! COMMA(44) call error('missing comma in DEFINE.') ! else got (name, end if nlpar = 0 i = 1 while (nlpar .ge. 0) do if (i .gt. defsiz) then call error('definition too long.') else if (ngetc(defn(i)) .eq. -1) then ! EOF(-1) call error('missing right paren.') else if (defn(i) .eq. 40) then ! LPAREN(40) nlpar = nlpar + 1 else if (defn(i) .eq. 41) then ! RPAREN(41) nlpar = nlpar - 1 ! else normal character in defn(i) end if i = i + 1 end while defn(i-1) = -2 ! EOS(-2) return end
最近のコメント