# include "seven/types.h"
# include "seven/macros.h"
* The symbol table size is set to a limit of forty keywords per input
* file. Should this limit be changed it should also be changed in the
struct symtab Sym
[SYMSIZE
];
* Delflag is used to indicate when text is to be skipped. It is decre-
* mented whenever an if condition is false, or when an if occurs
* within a false if/end statement. It is decremented whenever an end is
* encountered and the Delflag is greater than zero. Whenever Delflag
* is greater than zero text is skipped.
* Ifcount keeps track of the number of ifs and ends. Each time
* an if is encountered Ifcount is incremented and each time an end is
* encountered it is decremented.
* The main program reads a line of text and sends it to be processed
* if it is a version control statement. If it is a line of text and
* the Delflag is equal to zero, it is written to the standard output.
register char *lineptr
, *p
;
Fflags
= FTLCLN
| FTLMSG
| FTLEXIT
;
for(i
= 1; i
< argc
; i
++) {
while (fgets(line
,sizeof(line
),stdin
) != NULL
) {
for (p
= lineptr
; *p
; p
++)
if (lineptr
[0] != Ctlchar
) {
if (lineptr
[0] == '\\' && lineptr
[1] == Ctlchar
)
for (p
= &lineptr
[1]; *lineptr
++ = *p
++; )
if (imatch("if ", lineptr
))
else if (imatch("end", lineptr
))
if (imatch("asg ", lineptr
))
else if (imatch("dcl ", lineptr
))
else if (imatch("err", lineptr
))
else if (imatch("msg", lineptr
))
else if (lineptr
[0] == Ctlchar
)
else if (imatch("on", lineptr
))
else if (imatch("off", lineptr
))
else if (imatch("ctl ", lineptr
))
else error("unknown command on line %d (901)",Lineno
);
for(i
= 0; Sym
[i
].usage
!= 0 && i
<SYMSIZE
; i
++) {
if ((Sym
[i
].usage
&USD
) == 0)
warn("`%s' never used (902)\n",Sym
[i
].name
);
if ((Sym
[i
].usage
&DCL
) == 0)
warn("`%s' never declared (903)\n", Sym
[i
].name
);
if ((Sym
[i
].usage
&ASG
) == 0)
warn("`%s' never assigned a value (920)\n", Sym
[i
].name
);
error("`if' with no matching `end' (904)");
* Asgfunc accepts a pointer to a line picks up a keyword name, an
* equal sign and a value and calls putin to place it in the symbol table.
register char *end
, *aname
;
aptr
= findstr(aptr
,"= \t");
if (*aptr
== ' ' || *aptr
== '\t') {
error("syntax on line %d (917)",Lineno
);
* Dclfunc accepts a pointer to a line and picks up keywords
* separated by commas. It calls putin to put each keyword in the
* symbol table. It returns when it sees a newline.
register char *end
, *dname
;
if (Sym
[i
= lookup(dname
)].usage
&DCL
)
error("`%s' declared twice on line %d (905)",
* Errfunc calls fatal which stops the process.
warn("ERROR:%s\n",replace(eptr
));
error("err statement on line %d (915)", Lineno
);
* Endfunc indicates an end has been found by decrementing the if count
* flag. If because of a previous if statement, text was being skipped,
* Delflag is also decremented.
error("`end' without matching `if' on line %d (910)",Lineno
);
* Msgfunc accepts a pointer to a line and prints that line on the
warn("Message(%d):%s\n", Lineno
, replace(mptr
));
fprintf(stdout
,"%s\n",replace(s
));
* Iffunc and the three functions following it, door, doand, and exp
* are responsible for parsing and interperting the condition in the
* if statement. The BNF used is as follows:
* <iffunc> ::= [ "not" ] <door> EOL
* <door> ::= <doand> | <doand> "|" <door>
* <doand>::= <exp> | <exp> "&" <doand>
* <exp>::= "(" <door> ")" | <value> <operator> <value>
* <operator>::= "=" | "!=" | "<" | ">"
* And has precedence over or. If the condition is false the Delflag
* is bumped to indicate that lines are to be skipped.
* An external variable, sptr is used for processing the line in
* iffunc, door, doand, exp, getid.
* Iffunc accepts a pointer to a line and sets sptr to that line. The
* rest of iffunc, door, and doand follow the BNF exactly.
if (imatch("not ", sptr
)) {
error("syntax on line %d (918)",Lineno
);
* After exp checks for parentheses, it picks up a value by calling getid,
* picks up an operator and calls getid to pick up the second value.
* Then based on the operator it calls either numcomp or equal to see
* if the exp is true or false and returns the correct value.
else error("parenthesis error on line %d (911)",Lineno
);
if (op
== NEQ
&& (next
= *sptr
++) == '\0')
if(op
==LT
|| op
== GT
) {
value
= numcomp(id1
, id2
);
if ((op
== GT
&& value
== 1) || (op
== LT
&& value
== -1))
else if (op
==EQ
|| (op
==NEQ
&& next
==EQ
)) {
else error("invalid operator on line %d (912)", Lineno
);
* Getid picks up a value off a line and returns a pointer to the value.
gptr
= findstr(gptr
,DELIM
);
* Numcomp accepts two pointers to strings of digits and calls numck
* to see if the strings contain only digits. It returns -1 if
* the first is less than the second, 1 if the first is greater than the
* second and 0 if the two are equal.
register char *id1
, *id2
;
if ((k1
= size(id1
)) > (k2
= size(id2
)))
else while(*id1
!= '\0') {
* Numck accepts a pointer to a string and checks to see if they are
* all digits. If they're not it calls fatal, otherwise it returns.
for (; *nptr
!= '\0'; nptr
++)
error("non-numerical value on line %d (914)",Lineno
);
* Replace accepts a pointer to a line and scans the line for a keyword
* enclosed in control characters. If it doesn't find one it returns
* a pointer to the begining of the line. Otherwise, it calls
* lookup to find the keyword.
* It rewrites the line substituting the value for the
* keyword enclosed in control characters. It then continues scanning
* the line until no control characters are found and returns a pointer to
* the begining of the new line.
# define INCR(int) if (++int==NSLOTS) error(subrng,Lineno)
char *subrng
"out of space [line %d] (916)";
register char *s
, *t
, *p
;
for (s
=ptr
; *s
++!='\n';);
for (p
=ptr
; *(s
=findch(p
,Ctlchar
)); p
=t
) {
if (*(t
=findch(s
,Ctlchar
))==0)
error("unmatched `%c' on line %d (907)",Ctlchar
,Lineno
);
slots
[i
] = Sym
[j
= lookup(s
)].value
;
newlen
=+ (size(slots
[j
])-1);
t
= Repflag
= alloc(++newlen
);
* Lookup accepts a pointer to a keyword name and searches the symbol
* table for the keyword. It returns its index in the table if its there,
* otherwise it puts the keyword in the table.
register struct symtab
*s
;
((i
.chr
>='A' && i
.chr
<='Z') || (i
.chr
>='a' && i
.chr
<='z') ||
(i
.chr
!= *lname
&& i
.chr
>='0' && i
.chr
<='9')));
error("invalid keyword name on line %d (909)",Lineno
);
for(i
=0; Sym
[i
].usage
!= 0 && i
<SYMSIZE
; i
++)
if (equal(lname
, Sym
[i
].name
)) return(i
);
copy("",(s
->value
= alloc(s
->lenval
= 1)));
error("out of space (906)");
* Putin accepts a pointer to a keyword name, and a pointer to a value.
* It puts this information in the symbol table by calling lookup.
* It returns the index of the name in the table.
register struct symtab
*s
;
s
= &Sym
[i
= lookup(pname
)];
s
->lenval
= size(pvalue
);
copy(pvalue
, (s
->value
= alloc(s
->lenval
)));
error("keyword name too long on line %d (908)",Lineno
);
for (s
=astr
; (c
= *s
) && c
!=match
; s
++)
error("syntax on line %d (919)",Lineno
);
for (t
= (temp
=s
) + 1; *s
++ = *t
++;);
fatal(sprintf(Error
,"%r",&arg
));
for (s
=astr
; (c
= *s
) && any(c
,pat
)==0; s
++)
error("syntax on line %d (919)",Lineno
);
for (t
= (temp
=s
) + 1; *s
++ = *t
++;);
fprintf(stderr
,"%r",&arg
);