Ejemplo n.º 1
0
Archivo: gram.c Proyecto: joequant/iraf
int 
crackident (char *s)
{
	struct keywords {
		char *k_name;		/* the keyword string itself.	*/
		short k_token;		/* yacc %token for the keyword	*/
		short k_yylval;		/* the value associated with token.*/
	};

	static struct keywords kw[] = {

	    /* Control flow keywords.
	     */
	    { "while",  Y_WHILE,  0 },	{ "if",        Y_IF,        0 },
	    { "else",   Y_ELSE,   0 },	{ "switch",    Y_SWITCH,    0 },
	    { "case",   Y_CASE,   0 },	{ "default",   Y_DEFAULT,   0 },
	    { "break",  Y_BREAK,  0 },	{ "next",      Y_NEXT,      0 }, 
	    { "return", Y_RETURN, 0 },	{ "goto",      Y_GOTO,      0 },
	    { "for",    Y_FOR,    0 },	{ "procedure", Y_PROCEDURE, 0 },
	    { "begin",  Y_BEGIN,  0 },	{ "end",       Y_END,       0 },
	    { "iferr",  Y_IFERR,  0 },	{ "ifnoerr",   Y_IFNOERR,   0 },
	    { "then",   Y_THEN,   0 },

	    /* Parameter and variable types.
	     */
	    { "int",    Y_INT,    0 },	{ "char",      Y_STRING,    0 },
	    { "real",   Y_REAL,   0 },	{ "string",    Y_STRING,    0 },
	    { "file",   Y_FILE,   0 },	{ "gcur",      Y_GCUR,      0 },
	    { "imcur",  Y_IMCUR,  0 },	{ "ukey",      Y_UKEY,      0 },
	    { "pset",   Y_PSET,   0 },	{ "bool",      Y_BOOL,      0 },
	    { "struct", Y_STRUCT, 0 },

	    /* debugging commands.
	     */
	    { "d_d",    D_D,      0 },
	    { "d_peek", D_PEEK,   0 },

	    { "", 0, 0 } 		/* sentinel; leave it here... */
	};

	static struct keywords kf[] = {
	    /* Keywords of intrinsic functions that get built into
	     * the grammar.  Most intrinsics handled by intrinsic().
	     */
	    { "scan",   Y_SCAN,   0 },
	    { "scanf",  Y_SCANF,  0 },
	    { "fscan",  Y_FSCAN,  0 },
	    { "fscanf", Y_FSCANF, 0 },

	    /* sentinel; leave it here... */
	    { "", 0, 0 } 
	};

	register struct keywords *kp;
	XINT	oldtopd;
	static	char sch, kch;		/* static storage is faster here   */
	char	*scopy;			/* non-makelower'd copy		   */
	char    sb[REALWIDTH];


	oldtopd = topd;			/* save topd			   */
	scopy = comdstr(s);		/* make a copy in the dictionary   */
	makelower (scopy);		/* make it lower case for compares */
	topd = oldtopd;			/*restore topd but scopy still there!*/

	/* Put the first character of the identifier we are searching for
	 * in local storage to permit fast rejection of keywords without all
	 * the overhead involved in a call to strcmp.  This is an easy way
	 * to speed things up several times w/o coding fancy data structures.
	 */
	sch = *scopy;
	kch = *s;	/* save original string */

	/* Check for and handle special-case keywords first.
	 */
	if (sch == *truestr && !strcmp (scopy, truestr)) {
	    yylval = addconst (truestr, OT_BOOL);
	    return (Y_CONSTANT);
	} else if (sch == *falsestr && !strcmp (scopy, falsestr)) {
	    yylval = addconst (falsestr, OT_BOOL);
	    return (Y_CONSTANT);
	} else if (sch == *indeflc && !strcmp (scopy, indeflc)) {
	    yylval = addconst (scopy, OT_INT);
	    return (Y_CONSTANT);
	} else if (sch == *eoflc && !strcmp (scopy, eoflc)) {
	    yylval = addconst (CL_EOFSTR, OT_INT);
	    return (Y_CONSTANT);
	} else if (sch == *errorstr && !strcmp (scopy, errorstr)) {
	    yylval = addconst (errorstr, OT_STRING);
	    return (Y_IDENT);

	/* Check for defined numerical constants.  For backwards compatability
	 * we match 'epsilon', however this particular value is deprecated by
	 * the fp_equal() builtin and we assume CL constants will be upper
	 * case strings.
	 */
	} else if ((sch == *epsilonstr && !strcmp (scopy, epsilonstr)) ||
		   (kch == *epsilonuc && !strcmp (s, epsilonuc))) {
	    sprintf (sb, "%e", EPSILON);
	    yylval = addconst (sb, OT_REAL);
	    return (Y_CONSTANT);

	} else if (const_str (pistr)) { 	retconst (PI);
	} else if (const_str (twopistr)) { 	retconst (TWOPI);
	} else if (const_str (fourpistr)) { 	retconst (FOURPI);
	} else if (const_str (halfpistr)) { 	retconst (HALFPI);
	} else if (const_str (sqrtpistr)) { 	retconst (SQRTOFPI);
	} else if (const_str (sqrttwostr)) { 	retconst (SQRTOF2);
	} else if (const_str (baseestr)) { 	retconst (BASE_E);
	} else if (const_str (ln2str)) { 	retconst (LN_2);
	} else if (const_str (ln10str)) { 	retconst (LN_10);
	} else if (const_str (lnpistr)) { 	retconst (LN_PI);
	} else if (const_str (logestr)) { 	retconst (LOG_E);
	} else if (const_str (gammastr)) { 	retconst (GAMMA);
	} else if (const_str (radianstr)) { 	retconst (RADIAN);

	} else if (const_str (austr)) { 	retconst (AU);
	} else if (const_str (gaccelstr)) { 	retconst (GRAV_ACCEL);
	} else if (const_str (gconststr)) { 	retconst (GRAV_CONST);
	} else if (const_str (lystr)) { 	retconst (LIGHT_YEAR);
	} else if (const_str (parsecstr)) { 	retconst (PARSEC);
	} else if (const_str (lightstr)) { 	retconst (SPEED_OF_LIGHT);
	} else if (const_str (solmassstr)) { 	retconst (SOLAR_MASS);


	} else if (!inarglist && parenlevel == 0) {
	    /* Search the keyword list; kewords are not recognized in argument
	     * lists and expressions, else unquoted strings like "for" and
	     * "file" will cause syntax errors.
	     */
	    for (kp=kw;  (kch = *kp->k_name);  kp++)
		if (kch == sch)
		    if (strcmp (scopy, kp->k_name) == 0) {
			yylval = kp->k_yylval;
			return (kp->k_token);
		    }

	} else {
	    /* Search the list of intrinsic functions.
	     */
	    for (kp=kf;  (kch = *kp->k_name);  kp++)
		if (kch == sch)
		    if (strcmp (scopy, kp->k_name) == 0) {
			yylval = kp->k_yylval;
			return (kp->k_token);
		    }
	}

	/* S not a keyword, so it's just an identifier.
	 */
	yylval = addconst (s, OT_STRING);	/* use original */
	return (Y_IDENT);
}
Ejemplo n.º 2
0
/* LEXICON -- Simple "conversational mode" lexical analyser.  Lexical analysis
 * in the CL is carried out by a dual mode lexical analyser.  In conversational
 * mode there are few tokens and few special characters; arguments are
 * delimited by whitespace and may contain nonalphanumeric characters.  Few
 * strings have to be quoted.  In computational mode the arithmetic operators
 * are recognized and arguments must be delimited by commas.  Computational
 * mode is in effect whenever the parenlevel is nonzero.
 *
 * The two modes are implemented with two separate lexical analyzers.  Gettok
 * implements conversational mode, while computational mode is implemented with
 * a LEX finite state automaton.  Gettok recognizes the following special chars:
 *
 *	[ \t]				argument delimiter
 *	["']				string
 *	\n				newline
 *	\				single character escape
 *	!				os escape
 *	#				comment
 *	&				spawn background job
 *	(				lparen
 *	+				plus (switch)
 *	-				minus (switch)
 *	;				eost
 *	=				equals
 *	+=				add and set
 *	-=				subtract and set
 *	*=				multiply and set
 *	/=				divide and set
 *	<				redirin
 *	>				redir
 *	>&				allredir
 *	>>				append
 *	>>&				allappend
 *	>(G|I|P|)+			graphics stream redirection
 *	{				lbrace
 *	|				pipe
 *	|&				allpipe
 *	}				rbrace
 *	[				beginning of index list
 *	]				end of index list
 *
 * The history metacharacter ^ is processed before input is passed to the
 * lexical analyser.  Any sequence of nonwhite characters that does not form
 * one of the recognized tokens is returned as a string.
 */
int 
lexicon (void)
{
	char	*bkgerr = "ERROR: cannot submit background job inside {}\n";
	register int	ch, cch;
	register int	token;
	int	stringtok, identifier, setlevel;
	int	clswitch;
	char	*op, *index();

	/* Return pushed back token if any.
	 */
	if (pbtoken) {
	    token = pbtoken;
	    pbtoken = 0;
	    return (token);
	}

	/* Skip leading whitespace.  If whitespace is seen and we are in an
	 * argument list (according to the parser) set flag to output the
	 * comma argument delimiter if the next token begins an argument.
	 * If whitespace or = is seen (except whitespace at the beginning of
	 * a command) then set LHS to false, turning [] off as conversational
	 * mode metacharacters (they will be automatically turned on when
	 * compute mode is entered in an expression).
	 */
	while (ch = input())
	    if (ch == ' ' || ch == '\t') {
space:		if (lexcol > 0)
		    lhs = 0;
		if (inarglist)
		    newarg++;
	    } else if (ch == '\\') {
		if ((ch = input()) != '\n') {
		    unput (ch);
		    break;
		} else
		    goto space;
	    } else
		break;
	

	/* Start new token.
	 */
	if (ch) {
	    unput (ch);
	    yyleng = 0;
	    if (!inarglist)
		newarg = 0;
	} else
	    return (0);


	/* Identify and accumulate next token.  Simple tokens are returned as
	 * integer constants, more complex tokens as operand structures in
	 * yylval.
	 */
	while (ch = input()) {
	    lexcol++;

	    switch (ch) {
	    case '&':
		/* An ampersand triggers bkg execution in command mode, unless
		 * it occurs in a token such as >& or >>&, in which case we
		 * never get here.
		 */
		if (!newtoken) {
		    unput (ch);
		    goto tokout_;
		} else {
		    while (ch = input()) {
			if (ch == ' ' || ch == '\t')
			    continue;
			else {
			    char   bkgmsg[SZ_LINE+1];
			    int    n = SZ_LINE;

			    op = bkgmsg;
			    unput (ch);
			    if (bracelevel) {
				eprintf (bkgerr);
				return ('#');
			    }

			    while (--n >= 0 && (*op = input()) != '\n')
				op++;
			    *op = EOS;
			    bkg_init (bkgmsg);
			    return (Y_NEWLINE);
			}
		    }
		    return (0);
		}

	    case ';':
	    case '\n':
		lexcol = 0;
		lhs = 1;
		goto etok_;

	    case '\t':
	    case ' ':
		if (lexcol > 0)
		    lhs = 0;
		goto etok_;

	    case '[':
	    case ']':
		/* [] are recognized as command mode metacharacters only
		 * on the left hand side of an assignment statement.
		 */
		if (!lhs)
		    goto deposit_;
		/* Fall through */

	    case '{':
	    case '}':
		/* We want to distinguish here between the use of {} for
		 * the set selection operator in template strings, and the
		 * conventional compound statement operator.  The distinction
		 * is that { is recognized as a token only if occurs at the
		 * beginning of a token, and } is recognized as a separate
		 * token when inside a token only if it matches a { in the
		 * same token.  Hence, alpha{xxx} is a single token in command
		 * mode, whereas {xxx} is 3 tokens, the same as { xxx },
		 * and xxx} is the same as xxx }.  Usage is completely
		 * unambiguous if the { or } is preceded by a space.
		 */
		if (newtoken)
		    return (ch);
		if (stringtok) {
		    if (ch == '{')
			setlevel++;
		    else if (setlevel == 0)
			goto etok_;		/* } does not match { */
		    else
			--setlevel;
		    goto deposit_;
		}
		/* fall through */

	    case '=':
etok_:		if (!newtoken) {
		    unput (ch);
		    goto tokout_;
		} else if (ch == '\n') {
		    return (Y_NEWLINE);
		} else if (ch == '=') {
		    token = ch;
		    lhs = 0;
		    goto eatwhite_;
		} else
		    return (ch);

	    case '?':
		/* ?, ?? menu commands, recognized only at beginning of stmt */
		if (lexcol > 1) {
		    goto deposit_;
		} else if (ch = input()) {
		    if (ch == '?')
			return (crackident ("??"));
		    else {
			unput (ch);
			return (crackident ("?"));
		    }
		} else
		    return (0);

	    case '+':
	    case '-':
		/* Plus and minus are recognized as the switch operators for
		 * boolean parameters only if encountered while accumulating
		 * a token and if followed by an argument delimiter, i.e.,
		 * space, tab, newline, or semicolon.  If found at the beginning
		 * of a token they are returned as a separate token and will be
		 * interpreted by the parser as unary plus or minus.
		 */
		if (newtoken) {
		    if (newarg) {
			cch = input();
			if (cch == 0)
			    return (0);
			unput (cch);

			if (ch == '-' && isdigit (cch)) {
			    unput (ch);
			    newarg = 0;
			    return (',');
			} else {
			    /* Not number; treat +- as a string char.
			     */
			    goto deposit_;
			}

		    } else {
			cch = input();
			if (cch == 0)
			    return (0);

			if (cch == '=') {
			    if (ch == '+')
				return (YOP_AOADD);
			    else
				return (YOP_AOSUB);
			} else if (isdigit (cch)) {
			    unput (cch);
			    return (ch);
			} else {
			    unput (cch);
			    goto deposit_;
			}
		    }

		} else if (cch = input()) {
		    clswitch = (isspace (cch) || cch == ';');
		    if (cch == '=') {
			unput(cch);
			unput (ch);
			goto tokout_;
		    }
		    unput (cch);
		    if (clswitch) {
			pbtoken = ch;
			goto tokout_;
		    } else
			goto deposit_;
		} else
		    return (0);

	    case '"':
	    case '\'':
		if (!newtoken) {
		    unput (ch);
		    goto tokout_;
		} else if (newarg) {
		    unput (ch);
		    newarg = 0;
		    return (',');
		} else {
		    traverse (ch);
		    yylval = addconst (yytext, OT_STRING);
		    return (Y_CONSTANT);
		}

	    case '\\':
		if (ch = input()) {
		    if (ch == '\n')
			continue;
		    else if (index ("&;=+-\"'\\#><()|", ch) != NULL)
			goto deposit_;		/* put ch in string */
		    else
			goto escape_;		/* put \ch in string */
		} else
		    return (0);

	    case '!':
		/* OS escape is only recognized when the ! occurs as the first
		 * token in a statement.
		 */
		if (lexcol > 1)
		    goto deposit_;

		/* Accumulate command.  Newline may be escaped to enter a long
		 * command, but all other escapes are passed on unmodified.
		 */
		while ((ch = input()) && ch != '\n') {
		    if (ch == '\\')
			if (ch = input()) {
			    if (ch == '\n')
				continue;
			    else
				yytext[yyleng++] = '\\';
			} else
			    break;
		    yytext[yyleng++] = ch;
		}
		if (ch)
		    unput (ch);

		yytext[yyleng] = '\0';
		yylval = addconst (yytext, OT_STRING);
		return (Y_OSESC);

	    case '#':
		/* Discard the comment line. */
		while ((ch = input()) && ch != '\n')
		    ;
		if (ch) {
		    unput (ch);
		    continue;
		} else
		    return (0);

	    case '>':
	    case '<':
	    case '(':
		/* These characters are alike in that they all begin a new
		 * argument when found in an argument list.
		 */
		if (!newtoken) {
		    unput (ch);
		    goto tokout_;
		} else if (newarg) {
		    unput (ch);
		    newarg = 0;
		    return (',');
		} else if (ch == '<') {
		    token = ch;
		    goto eatwhite_;

		} else if (ch == '>') {
		    ch = input();
		    if (ch == 0) {
			return ('>');

		    } else if (ch == '>') {
			ch = input();
			if (ch == 0) {
			    return (Y_APPEND);
			} else if (ch == 'G' || ch == 'I' || ch == 'P') {
			    op = yytext;
			    *op++ = '>';
			    *op++ = '>';
			    *op++ = ch;
			    goto gsredir_;
			} else if (ch == '&') {
			    token = Y_ALLAPPEND;
			    goto eatwhite_;
			} else {
			    unput (ch);
			    token = Y_APPEND;
			    goto eatwhite_;
			}

		    } else if (ch == 'G' || ch == 'I' || ch == 'P') {
			/* Graphics stream redirection.
			 */
			op = yytext;
			*op++ = '>';
			*op++ = ch;
gsredir_:
			ch = input();
			while (ch == 'G' || ch == 'I' || ch == 'P') {
			    *op++ = ch;
			    ch = input();
			}
			unput (ch);
			*op = EOS;

			yylval = addconst (yytext, OT_STRING);
			token = Y_GSREDIR;
			goto eatwhite_;

		    } else if (ch == '&') {
			token = Y_ALLREDIR;
			goto eatwhite_;
		    } else {
			unput (ch);
			token = '>';
			goto eatwhite_;
		    }

		} else
		    return ('(');

	    case '|':
		if (!newtoken) {
		    unput (ch);
		    goto tokout_;
		} else if (ch = input()) {
		    if (ch == '&')
			return (Y_ALLPIPE);
		    else {
			unput (ch);
			return ('|');
		    }
		} else
		    return (0);

	    case '*':
	    case '/':
		cch = input();
		if (cch == 0)
		    return (0);

		if (newtoken) {
		    if (cch == '=')
			return ((ch=='*') ? YOP_AOMUL:YOP_AODIV);
		    else {
			unput (cch);
			goto deposit_;
		    }
		} else {
		    if (cch == '=') {
			unput (cch);
			unput (ch);
			goto tokout_;
		    } else {
			unput (cch);
			goto deposit_;
		    }
		}

	    /* The following cases are included to force the compiler
	     * to compile the case as an ASCII jump table.
	     */
	    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
	    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
	    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
	    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
	    case 'y': case 'z':
	    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
	    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
	    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
	    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
	    case 'Y': case 'Z':
		/* fall through to default */

	    default:
		goto deposit_;
escape_:	
		/* Deposit a character preceded by the escape character.
		 */
		if (!newarg) {
		    unput (ch);
		    ch = '\\';
		}
deposit_:
		/* If the last token returned was a string argument and we
		 * are starting a second, a delimiter token must be returned
		 * to delimit the two arguments.  Check for chars not legal
		 * in an identifier so that we can know whether to return
		 * CONSTANT or call crackident() which returns IDENT if not
		 * a reserved keyword.
		 */
		if (newtoken) {
		    identifier = 1;
		    stringtok  = 1;
		    setlevel   = 0;
		    if (newarg) {
			unput (ch);
			newarg = 0;
			return (',');
		    }
		}

		yytext[yyleng++] = ch;
		if (ch == '[') {
		    while ((ch = input()) != ']')
		        yytext[yyleng++] = ch;
		    yytext[yyleng++] = ch;
		} else if (ch == '\\')
		    yytext[yyleng++] = ch = input();
		else if (!(isalnum(ch) || ch == '_' || ch == '$' || ch == '.'))
		    identifier = 0;
	    }
	}

tokout_:
	yytext[yyleng] = '\0';

	if (isdigit (yytext[0]) || yytext[0] == '.' && isdigit (yytext[1])) {
	    int	token, toklen;

	    token = c_lexnum (yytext, &toklen);
	    if (token != LEX_NONNUM && toklen == yyleng) {
		switch (token) {
		case LEX_REAL:
		    yylval = addconst (yytext, OT_REAL);
		    break;
		default:
		    yylval = addconst (yytext, OT_INT);
		    break;
		}
		return (Y_CONSTANT);
	    }
	}

	if (identifier)
	    return (crackident (yytext));
	else {
	    yylval = addconst (yytext, OT_STRING);
	    return (Y_CONSTANT);
	}

eatwhite_:
	/* Control transfers here after a token has been identified which is
	 * followed by an associated argument (e.g. > file or < file).  Our
	 * function is to discard any whitespace following the current token
	 * in order to make whitespace optional in the input at this point.
	 * This makes "> file" (for example) equivalent to ">file".
	 */
	newarg = 0;
        while ((ch = input()) && (ch == ' ' || ch == '\t'))
	    ;
	if (ch) {
	    unput (ch);
	    return (token);
	} else
	    return (0);
}
Ejemplo n.º 3
0
static void doagentcmd(FILE *str,char *line)
{
    char *agentname;
    char *instances;
    char *inst;
    char *ptr;
    char regline[500];
    char cumlname[100];
    REGINFO regs[100];
    char temp[20];
    int rmax = 0;
    int idx;
    unsigned int cumlmask;
    int agentidx;

    agentname = gettoken(&line);
    instances = gettoken(&line);
    if (!instances) {
	strcpy(temp,"*");
	instances = temp;
	}

    fprintf(stderr,"Agent %s Instances %s\n",agentname,instances);

    if (agentcnt == MAXAGENTS) {
	fatal("Out of agent slots\n",NULL);
	}

    agentnames[agentcnt] = strdup(agentname);
    agentidx = agentcnt;
    agentcnt++;

    regline[0] = '\0';

    while ((readline(str,regline,sizeof(regline)) >= 0) && (rmax < 100)) {
	char *atext,*subinst,*pfunc,*descr;

	if (regline[0] == '!') break;

	ptr = regline;
	atext = gettoken(&ptr);
	subinst = gettoken(&ptr);
	pfunc = gettoken(&ptr);
	descr = gettoken(&ptr);

	if (!descr) {
	    fatal("Missing fields for ",atext);
	    }

	regs[rmax].reg_addr = strdup(atext);
	regs[rmax].reg_subinst = strdup(subinst);
	regs[rmax].reg_printfunc = strdup(pfunc);
	regs[rmax].reg_description = strdup(descr);
	regs[rmax].reg_mask = 0;
	rmax++;
	}

    if (rmax == 100) fatal("Too many registers in section ",agentname);

    inst = strtok(instances,",");

    cumlmask = 0;
    while (inst) {
	char defname[100];
	unsigned int curmask;

	sprintf(defname,"SOC_AGENT_%s%s",
		agentname,inst[0] == '*' ? "" : inst);

	curmask = newmask();
	cumlmask |= curmask;

	addconst(defname,curmask);

	for (idx = 0; idx < rmax; idx++) {
	    char descr[100];
	    char atext[200];

	    macroexpand(regs[idx].reg_addr,inst,atext);
#if 0
	    strcpy(descr,agentname);
	    if (inst[0] != '*') {
		strcat(descr,inst);
		}
	    strcat(descr," ");
	    if (regs[idx].reg_subinst[0] != '*') {
		strcat(descr,regs[idx].reg_subinst);
		strcat(descr," ");
		}
	    strcat(descr,regs[idx].reg_description);
#else
	    strcpy(descr,regs[idx].reg_description);
#endif

	    addreg(agentname,
		   agentidx,
		   curmask,
		   atext,
		   inst,
		   regs[idx].reg_subinst,
		   regs[idx].reg_printfunc,
		   descr);
	    }
	inst = strtok(NULL,",");
	}

    if (instances[0] != '*') {
	sprintf(cumlname,"SOC_AGENT_%s",agentname);
	addconst(cumlname,cumlmask);
	}
}