[comp.unix.wizards] argv --> stdin IN LEX

rbbb@rice.EDU (David Chase) (12/09/86)

RTFM! RTFM! RTFM!  I QUOTE:

	In addition to these routines, Lex also permits access to the
    I/O routines that it uses.  They are:

    1)	input() which returns the next input character;

    2)	output(c) which writes the character c on the
	output; and

    3)	unput(c) pushes the character c back onto the
	input stream to be read later by input().

    By default these routines are provided as macros definitions,
    but the user can override them and supply private versions.
    ....

Read the rest of "Lex- A Lexical Analyzer Generator" by M. E. Lesk and E.
Schmidt for other details, including the lookahead issues, use of yywrap,
etc.

>>"Look at the code generated by these tools!  It's easy to change it!"

David

mcvoy@uwvax.UUCP (12/11/86)

In article <1367@brl-adm.ARPA> rbbb@rice.EDU (David Chase) writes:
>RTFM! RTFM! RTFM!  I QUOTE:
>	In addition to these routines, Lex also permits access to the
>    I/O routines that it uses.  They are:
>    1)	input() which returns the next input character;
>    2)	output(c) which writes the character c on the
>	output; and
>    3)	unput(c) pushes the character c back onto the
>	input stream to be read later by input().
>
>    By default these routines are provided as macros definitions,
>    but the user can override them and supply private versions.
>    ....

  After RTFM! RTFM! RTFM!-ing again and wading through lex 
output (gag):  Yup.  Works neat.  With lex.  Doesn't work at all 
with yacc.  If y'all go back and read the original posting, you 
will notice that I kinda asked for a solution that works with 
lex and yacc.  
  
  The relevant parts of the code are included below.  My guess 
is that yacc makes some assumptions about buffers, though 
I can't see where.

  I've got a fix that has nothing to do with lex & yacc and I 
like it that way.  The original problem, which might occur in 
situations that don't use lex and yacc, is how do you send 
the chars in argv[] to a process that thinks it's getting
them from stdin?  The answer:  Use a pipe.  If you know that 
you have less than 4k or so, don't even bother to fork.  

Here's the offending code, if you're interested, be warned that 
I don't vouch for this, it's a hack:

---------------------- t.l ---------------------------
%{
# undef		input()
# undef		unput()
# define	input()		myinput()
# define	unput(c)	myunput(c)
# include	<stdio.h>
# include	"y.tab.h"
%}
DIGIT	[0-9]
DSEQ	"-"?{DIGIT}+
RSEQ	"-"?{DSEQ}"."{DSEQ}
EXPONP	("e"|"E")("-"|"+")?{DSEQ}
MULT	[xX*]
RPAR	[)rR]
LPAR	[(lL]
%%
"+"			return(PLUS);
"-"			return(MINUS);
{MULT}			return(MULTIPLY);
"/"			return(DIVIDE);
{LPAR}			return(LPAREN);
{RPAR}			return(RPAREN);
{DSEQ}			return(INT_CONST);
{RSEQ}			return(REAL_CONST);
({DSEQ}|{RSEQ}){EXPONP}	return(REAL_CONST);
\n			return(EOL);
[ \t]			;		/* white space, ignore */
.			{ printf("Scanner error: Illegal Character\n"); }
%%

char*	ptr;
char	buf[4096];

myinput()
{
    fprintf(stderr, "Input called, ptr = '%s'\n", ptr);
    return *ptr++;
}

myunput(c)
    char c;
{
    if (ptr == buf) {
	fprintf(stderr, "ERROR: tried to unput one too many (%c)\n", c);
	exit(1);
    }

    fprintf(stderr, "Unput called, ptr = '%s'\n", ptr);
    *--ptr = c;
}

main(argc, argv)
    char** argv;
{
    int 	i;
    char*	s;

    ptr = buf;
    for (i=1; i<argc; i++)
	for (s=argv[i]; *s; *ptr++ = *s++)
	    ;
    
    ptr = buf;
    printf("Sending %s to lex\n", buf);
    
# ifdef TESTLEX
    /* this works like a charm */
    while (i = yylex())
	printf("Lex returns %d\n", i);
# else
    /* this bombs */
    yyparse();
# endif
}

yyerror(s)
    char* s;
{
    fprintf(stderr, "%s\n");
}

---------------------- t.l ---------------------------

%{
#include <stdio.h>

extern char yytext[];
extern float atof();

static float result;
%}
%token
	PLUS MINUS MULTIPLY DIVIDE INT_CONST REAL_CONST LPAREN RPAREN EOL
%union
{
	float val;
}
%type
	<val>	root expr factor term
%%
root	:	expr EOL	{
				printf("%.4f\n",$1);
				exit(0);
				}
	;
expr	:	expr PLUS term	{ $$ = $1 + $3; }
	|	expr MINUS term { $$ = $1 - $3; }
	|	term
	;
term	:	term MULTIPLY factor	{ $$ = $1 * $3; }
	|	term DIVIDE factor	{ $$ = $1 / $3; }
	|	factor
	;
factor	:	INT_CONST	{ $$ = (float)atoi(yytext); }
	|	REAL_CONST	{ $$ = atof(yytext); }
	|	LPAREN expr RPAREN { $$ = $2; }
	;
-- 
Larry McVoy 	        mcvoy@rsch.wisc.edu, 
      		        {seismo, topaz, harvard, ihnp4, etc}!uwvax!mcvoy

"They're coming soon!  Quad-stated guru-gates!"

ejp@ausmelb.OZ (Esmond Pitt) (12/12/86)

In article <3060@rsch.WISC.EDU> mcvoy@rsch.WISC.EDU (Lawrence W. McVoy) writes:
>In article <1367@brl-adm.ARPA> rbbb@rice.EDU (David Chase) writes:
>>RTFM! RTFM! RTFM!  I QUOTE:
>
>  After RTFM! RTFM! RTFM!-ing again and wading through lex 
>output (gag):  Yup.  Works neat.  With lex.  Doesn't work at all 
>with yacc.  If y'all go back and read the original posting, you 
>will notice that I kinda asked for a solution that works with 
>lex and yacc.  
>  
>  The relevant parts of the code are included below.  My guess 
>is that yacc makes some assumptions about buffers, though 
>I can't see where.

Bad guess. Your code kinda has at least two bugs:

1. Your yyerror() function is wrong, so you didn't see the parser
trying to print 'syntax error'. (Why not use yyerror() from -ly?)

2. The syntax error occurs because the grammar expects a newline,
but you didn't append one to the argument buffer.

>main(argc, argv)
...
>    for (i=1; i<argc; i++)
>	for (s=argv[i]; *s; *ptr++ = *s++)
>	    ;
>    
!    *ptr++ = '\n';	/* Terminate argument list with newline	*/
>    ptr = buf;
...
>yyerror(s)
>    char* s;
>{
/*    fprintf(stderr, "%s\n");	*/	/* WRONG	*/
!     fprintf(stderr, "%s\n",s);	/* RIGHT	*/
>}

Fix & it works fine.
-- 
Esmond Pitt,				ACSnet: ejp@ausmelb.oz
Austec International Ltd,		UUCP: ...!seismo!munnari!ausmelb.oz!ejp
344 St Kilda Rd,			ARPA: ejp%ausmelb.oz@SEISMO.CSS.GOV
Melbourne, 3004, AUSTRALIA.		Phone: +61 3 699 4511; Telex: AA38559
D