[comp.lang.c] argv ==> stdin

mcvoy@rsch.WISC.EDU (Lawrence W. McVoy) (11/20/86)

Hi there.  I'm using lex & yacc to do some work for me and I can't 
quite get it.   The scanner & parser part works, but only if it's 
getting input from stdin.  I diddled lex.yy.c to change the getc(yyin)
call in the input() define to call my routine which feed sit characters 
from argv.  This works if I call yylex() from main, but if yyparse calls 
it then I get a "syntax error".  The same program works if I don't
diddle the input() routine.  And I can't figure out what's wrong
with my diddling.....

So, I'm stuck.  Does anyone have a cute way to feed a short byte stream
to stdin backwards?  Or a better solution?  I'm not willing to do 
anything as kludgey as

	#!/bin/sh

	cat << EOF | my_problem_program
	$*
	EOF

But that is _exactly_ what I want to do, only faster (no sh start up).
I suppose I could do the fork() and feed the child the command line as 
stdin, but even that is sort of yucko.

All suggestions welcome, and apologies to unix-wizards, but I figure you
don't read unix-questions anymore :-(

-- 
Larry McVoy 	        mcvoy@rsch.wisc.edu, 
      		        {seismo, topaz, harvard, ihnp4, etc}!uwvax!mcvoy

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

grady@ic.Berkeley.EDU (Steven Grady) (11/20/86)

I hope someone comes up with a good solution, because I'm not satisfied
with the way I had to handle it:

#include <stdio.h>

/* Make a file pointer point to a string */
FILE *
set_fp_to_str(fp, str)
FILE *fp;
char *str;
{

	/* Check out the src to sscanf, etc, for more fun.. */
	fp->_flag = _IOREAD|_IOSTRG;
	fp->_ptr = fp->_base = str;
	fp->_cnt = 0;
	while (*str++) {
	        fp->_cnt++;
	}
	fp->_bufsiz = fp->_cnt;
    	return(fp);
}

/* Use yyparse() on a string */
foo(str)
char *str;
{
	FILE tmp;

	/* Save old value of stdin */
	tmp = *stdin;
	set_fp_to_str(stdin, str);
	yyresult = yyparse();
	*stdin = tmp;
}

scabel@diku.UUCP (11/21/86)

In article <2972@rsch.WISC.EDU> mcvoy@rsch.WISC.EDU (Lawrence W. McVoy) writes:
>Hi there.  I'm using lex & yacc to do some work for me and I can't 
>quite get it.   The scanner & parser part works, but only if it's 
>getting input from stdin.  I diddled lex.yy.c to change the getc(yyin)
>call in the input() define to call my routine which feed sit characters 
>from argv.  This works if I call yylex() from main, but if yyparse calls 
>it then I get a "syntax error".  The same program works if I don't
>diddle the input() routine.  And I can't figure out what's wrong
>with my diddling.....

I have made a program using lex and yacc, which either reads from a
argument to the program, or from stdin.

Here is the important parts from the lex file..
%C
%{
#ifdef input
#undef input
#endif
# define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):nextchar())==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)

extern int ARGEXPR;
extern char *argexpr;
%}

%%
/* The lex program */
%%
int nextchar()
{
	static int i = 0;

	if (ARGEXPR) {
		if (*argexpr == '\0')
		    return(i++ == 0?'\n':EOF);
		return(*argexpr++);
	} else
	    return(getc(yyin));
}

-- 

Niels Schachtschabel,
Institute of Datalogy, University of Copenhagen
E-mail: scabel@diku.uucp / ...!seismo!mcvax!diku!scabel

mouse@mcgill-vision.UUCP (11/23/86)

In article <2972@rsch.WISC.EDU>, mcvoy@rsch.WISC.EDU (Lawrence W. McVoy) writes:
> So, I'm stuck.  Does anyone have a cute way to feed a short byte stream
> to stdin backwards?  Or a better solution?  I'm not willing to do 
> anything as kludgey as
[shell script hack]

This situation is made-to-order for one of my stdio extensions:

	FILE *fopenstr(str,len,mode)
	char *str;
	int len;
	char *mode;

which produces a stdio stream which reads from or writes into
(according as mode is "r" or "w") the given string.  For BSD systems at
least, this is easy (I believe someone already posted pretty much what
is necessary).  I don't know how easy it would be on a USG system.

There's also fopenfxn(), which makes stdio call a specified function
whenever it wants a character - with this you can build anything you
want.

					der Mouse

USA: {ihnp4,decvax,akgua,utzoo,etc}!utcsri!mcgill-vision!mouse
     think!mosart!mcgill-vision!mouse
Europe: mcvax!decvax!utcsri!mcgill-vision!mouse
ARPAnet: think!mosart!mcgill-vision!mouse@harvard.harvard.edu

[USA NSA food: terrorist, cryptography, DES, drugs, CIA, secret, decode]

jimbi@copper.UUCP (Jim Bigelow) (12/01/86)

In article <2972@rsch.WISC.EDU>, mcvoy@rsch.WISC.EDU (Lawrence W. McVoy) writes:
> Hi there.  I'm using lex & yacc to do some work for me and I can't 
> quite get it.   The scanner & parser part works, but only if it's 
> getting input from stdin.  I diddled lex.yy.c to change the getc(yyin)
> call in the input() define to call my routine which feed sit characters 
> from argv.  This works if I call yylex() from main, but if yyparse calls 

One method I haven't seen posted yet is to fopen a file name from argv and 
give yyin the value:

/* 
 *	main -- read command line params, open/process/close files
 */
#include <stdio.h>

extern FILE *yyin;		/* input to lexical analyzer */
extern char *func_name;

extern char *optarg;		/* used and set by getopt */
extern int optind; opterr;

int Debug = 0;			/* debug flag */
int Verbose = 0;		/* verbose flag */

usage(name)
	char *name;
{
	printf("Usage: %s [-lnv] func_name [file...]\n", name);
}

main (argc, argv) 
	int argc;
	char **argv;
{
	int c;

	while((c = getopt(argc, argv, "lnvdp:")) != EOF)
		switch(c) {
		case 'v':
			Verbose = 1;
			break;
		case 'd':
			Debug = 1;
			break;	
		case '?':
			usage(argv[0]);
			exit(1);
			break;
		}

	if(optind == argc)
		yylex();
	else 
		for(; optind < argc; optind++) {
			if(( yyin = fopen(argv[optind], "r"))== NULL) {
				printf("%s: cannot open %s\n",argv[0], argv[optind]);
			} else {
				yylex();
				fclose(yyin);
			}
		}
}

mikes@apple.UUCP (Mike Shannon) (12/03/86)

To people using yacc & lex and trying to read from a file, not stdin,
you should note that in the code generated by lex for reading a character,
a call is made to getc(yyin).
	yyin is simply a variable statically initialized to be stdin, but
you can *easily* re-assign it via a call to fopen(), as in
	yyin = fopen(argv[1])
	or some such.
	Look at the code generated by these tools!  It's easy to change it!
-- 
			Michael Shannon {apple!mikes}

mcvoy@rsch.WISC.EDU (Lawrence W. McVoy) (12/04/86)

In article <347@apple.UUCP> mikes@apple.UUCP (Mike Shannon) writes:
>To people using yacc & lex and trying to read from a file, not stdin,
>you should note that in the code generated by lex for reading a character,
>a call is made to getc(yyin).
>	yyin is simply a variable statically initialized to be stdin, but
>you can *easily* re-assign it via a call to fopen(), as in
>	yyin = fopen(argv[1])
>	or some such.

I've seen one too many of these float by to take it any more.  Please read
what I asked in the first place and answer that.  Your answers imply that 
I'm an idiot.  While that is sometimes true, it's not the case here:

From the original posting:
    Subject: Re: argv ==> stdin (fast)
    Keywords: make the commandline look like a file?
		       ^^^^^^^^^^^

I am _NOT_ asking how to use fopen.  Jeez.  I'm asking how to make the 
characters typed on the command line look like they are in a file.
From the point of view of lex/yacc.  For example if I said

% a.out 1+2/3

I want lex to see '1', '+', '2', '/', '3' EOF

By the way, I have a zillion solutions, and thanks go out to all who
replied.  The best one said "get a pipe, stuff argv into it, close 
stdin, dup the read side of the pipe".  Sorry, I can't remember who
sent it, but thanks anyways...

>	Look at the code generated by these tools!  It's easy to change it!
>-- 
>			Michael Shannon {apple!mikes}

Look at the posting generated by these fingers!  It's easy to read!
-- 
Larry McVoy 	        mcvoy@rsch.wisc.edu, 
      		        {seismo, topaz, harvard, ihnp4, etc}!uwvax!mcvoy

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