mods to expr(1) for unary minus operator

Dave Steffens das at earvax.UUCP
Tue Aug 12 04:38:58 AEST 1986


Index: src/bin/expr.y

Several months ago I posted in net.bugs.4bsd a fix to expr(1) so that it
would handle negative arguments correctly.  In the discussion that followed
it was pointed out that my fix fails to correctly handle the case:
	expr --5 + 1

I feel that this should be an error since "--5" is not a legal number.
If the unary minus operator is what is wanted, the correct syntax is:
	expr - -5 + 1
since the manual page states each token must be a separate argument.

Well, the original expr(1) doesn't have unary minus so I just ignored this.
But recently I have had some need for unary minus so I decided to add it.
I have also added a test which makes "--5" an error under arithmetic
operators and a string under compare operators so that:
	expr --5 \<= --4
correctly gives 0.  In my original fix this gave 1 because both args
were treated as numbers and "atol()" returns 0 when passed illegal strings.

One possible disadvantage of this modification is that several undocumented
operators ("match", "length", "index" and "substr") must be deleted in order
to pass yacc without reduce/reduce conflicts.  However, in the discussion
someone said these operators have already been removed from SYSV source,
probably because they were found to cause trouble in string matches.

In the diffs that follow I have used the original 4.2bsd version of expr.y
so my negative argument fix is included for those who might have missed it.

1c1,10
< /* Yacc productions for "expr" command: */
---
> /*
>  * Yacc productions for "expr" command
>  *
>  * 4.2bsd version
>  * Modified to handle negative numbers as arguments, DAS JUN-86
>  * Modified to avoid "illegal pointer op" messages, DAS JUN-86
>  * Added unary minus, DAS AUG-86
>  * Deleted code for undocumented operators, DAS AUG-86
>  * Improved definition of and testing for legal numbers, DAS AUG-86
>  */
3,4c12,14
< %token OR AND ADD SUBT MULT DIV REM EQ GT GEQ LT LEQ NEQ
< %token A_STRING SUBSTR LENGTH INDEX NOARG MATCH
---
> %union {
> 	char *s;
> }
5a16,20
> %type  <s> expr
> %token <s> A_STRING
> 
> %token OR AND ADD SUBT MULT DIV REM EQ GT GEQ LT LEQ NEQ NOARG
> 
11a27
> %right UMINUS
13,15d28
< %left MATCH
< %left SUBSTR
< %left LENGTH INDEX
40a54
> 	| SUBT expr %prec UMINUS   = { $$ = arith(SUBT, "0", $2); }
42,45d55
< 	| MATCH expr expr = { $$ = match($2, $3); }
< 	| SUBSTR expr expr expr = { $$ = substr($2, $3, $4); }
< 	| LENGTH expr       = { $$ = length($2); }
< 	| INDEX expr expr = { $$ = index($2, $3); }
48a59
> 
71,72c82,83
< 	"=", "==", "<", "<=", ">", ">=", "!=",
< 	"match", "substr", "length", "index", "\0" };
---
> 	"=", "==", "<", "<=", ">", ">=", "!=", "\0" };
> 
74,75c85,86
< 	EQ, EQ, LT, LEQ, GT, GEQ, NEQ,
< 	MATCH, SUBSTR, LENGTH, INDEX };
---
> 	EQ, EQ, LT, LEQ, GT, GEQ, NEQ, };
> 
90c101
< 	yylval = p;
---
> 	yylval.s = p;
93a105,106
> #define ISNUMBER(x) (ematch(x, "-*[0-9]*$") && !ematch(x, "--"))
> 
97c110
< 	if(ematch(r1, "-*[0-9]*$") && ematch(r2, "[0-9]*$"))
---
> 	if (ISNUMBER(r1) && ISNUMBER(r2))
116c129
< 	if(!(ematch(r1, "[0-9]*$") && ematch(r2, "[0-9]*$")))
---
> 	if (!ISNUMBER(r1) || !ISNUMBER(r2))
131a145
> 
162,201d175
< char *substr(v, s, w) char *v, *s, *w; {
< 	... code deleted ...
< }
< 
< char *length(s) register char *s; {
< 	... code deleted ...
< }
< 
< char *index(s, t) char *s, *t; {
< 	... code deleted ...
< }
< 

-- 
{harvard,mit-eddie,think}!eplunix!earvax!das	David Allan Steffens
243 Charles St., Boston, MA 02114		Eaton-Peabody Laboratory
(617) 523-7900 x2748				Mass. Eye & Ear Infirmary



More information about the Comp.bugs.2bsd mailing list