X/*
X * Bawk C actions parser
X */
X#include <stdio.h>
X#include "bawk.h"
X
Xstatic char operator_strength[] = {
X0,  /* 0 */
X0,  /* CHAR */
X0,  /* BOL */
X0,  /* EOL */
X0,  /* ANY */
X0,  /* CLASS */
X0,  /* NCLASS */
X0,  /* STAR */
X0,  /* PLUS */
X0,  /* MINUS */
X0,  /* ALPHA */
X0,  /* DIGIT */
X0,  /* NALPHA */
X0,  /* PUNCT */
X0,  /* RANGE */
X0,  /* ENDPAT */
X0,  /* T_STRING */
X0,  /* T_DOLLAR */
X0,  /* T_REGEXP */
X0,  /* T_REGEXP_ARG */
X0,  /* T_CONSTANT */
X0,  /* T_VARIABLE */
X0,  /* T_FUNCTION */
X0,  /* T_SEMICOLON */
X0,  /* T_EOF */
X0,  /* T_LBRACE */
X0,  /* T_RBRACE */
X0,  /* T_LPAREN */
X0,  /* T_RPAREN */
X0,  /* T_LBRACKET */
X0,  /* T_RBRACKET */
X0,  /* T_COMMA */
X1,  /* T_ASSIGN */
X0,  /* T_STAR */
X11, /* T_MUL */
X11, /* T_DIV */
X11, /* T_MOD */
X10, /* T_ADD */
X0,  /* T_UMINUS */
X10, /* T_SUB */
X9,  /* T_SHL */
X9,  /* T_SHR */
X8,  /* T_LT */
X8,  /* T_LE */
X8,  /* T_GT */
X8,  /* T_GE */
X7,  /* T_EQ */
X7,  /* T_NE */
X0,  /* T_NOT */
X0,  /* T_ADDROF */
X6,  /* T_AND */
X5,  /* T_XOR */
X4,  /* T_OR */
X0,  /* T_LNOT */
X3,  /* T_LAND */
X2,  /* T_LOR */
X0,  /* T_INCR */
X0,  /* T_DECR */
X0,  /* T_POSTINCR */
X0,  /* T_POSTDECR */
X0,  /* T_IF */
X0,  /* T_ELSE */
X0,  /* T_WHILE */
X0,  /* T_BREAK */
X0,  /* T_CHAR */
X0,  /* T_INT */
X0,  /* T_BEGIN */
X0,  /* T_END */
X0,  /* T_NF */
X0,  /* T_NR */
X0,  /* T_FS */
X0,  /* T_RS */
X0,  /* T_FILENAME */
X0,  /* T_STATEMENT */
X0,  /* T_DECLARE */
X0   /* T_ARRAY_DECLARE */
X};
X
XEXPR_NODE *stmt_parse()
X{
X	/*
X	 * Parse a statement.
X	 */
X	register EXPR_NODE *root = NULL, *end_pointer, *tmp;
X
X	DBUG_ENTER("stmt_parse");
X	switch ( Token )
X	{
X	case T_EOF:
X		break;
X	case T_CHAR:
X	case T_INT:
X		root = declist_parse();
X		break;
X	case T_LBRACE:
X		/*
X		 * parse a compound statement
X		 */
X		getoken();
X		while ( Token != T_RBRACE )
X		{
X			tmp = get_expr_node((char) T_STATEMENT);
X			if(!root) {
X				root = end_pointer = tmp;
X			} else {
X				end_pointer->right = tmp;
X				end_pointer = tmp;
X			}
X			end_pointer->left = stmt_parse();
X		}
X		if ( Token==T_RBRACE )
X			getoken();
X		break;
X	case T_IF:
X		/*
X		 * parse an "if-else" statement
X		 */
X		if ( getoken() != T_LPAREN )
X			syntaxerror();
X		getoken();
X		root = get_expr_node((char) T_IF);
X		root->left = end_pointer = get_expr_node((char) T_IF);
X		end_pointer->left = expr_parse();
X		if ( Token!=T_RPAREN )
X			syntaxerror();
X		getoken();
X		end_pointer->right = stmt_parse();
X		if ( Token==T_ELSE )
X		{
X			getoken();
X			root->right = stmt_parse();
X		}
X		break;
X	case T_WHILE:
X		/*
X		 * parse a "while" statement
X		 */
X		root = get_expr_node((char) T_WHILE);
X		if ( getoken() != T_LPAREN )
X			syntaxerror();
X
X		getoken();
X		root->left = expr_parse();
X		if ( Token!=T_RPAREN )
X			syntaxerror();
X
X		getoken();
X		root->right = stmt_parse();
X		break;
X	case T_BREAK:
X		/*
X		 * parse a "break" statement
X		 */
X		root = get_expr_node((char) T_BREAK);
X		getoken();
X		break;
X	case T_SEMICOLON:
X		break;
X	default:
X		root = expr_parse();
X	}
X
X	if ( Token==T_SEMICOLON )
X		getoken();
X	DBUG_RETURN(root);
X}	
X
XEXPR_NODE *expr_parse()
X{
X	register EXPR_NODE *root, *tmp;
X	register char strength;
X
X	DBUG_ENTER("expr_parse");
X	strength = operator_strength[T_ASSIGN];
X	root = expr_left_to_right_parse(strength);
X	if(strength == operator_strength[Token])
X	{
X		/* assignments are grouped right to left */
X		tmp = get_expr_node(Token);
X		tmp->left = root;
X		root = tmp;
X		getoken();
X		root->right = expr_parse();
X	}
X	DBUG_RETURN(root);
X}
X
XEXPR_NODE *expr_left_to_right_parse(parent_strength)
Xregister char parent_strength;
X{
X	register EXPR_NODE *root, *tmp;
X	register char strength; 
X
X	DBUG_ENTER("expr_left_to_right_parse");
X	root = primary_parse();
X	if(parent_strength < (strength = operator_strength[Token]))
X	{
X		while(strength == operator_strength[Token])
X		{
X			tmp = get_expr_node(Token);
X			tmp->left = root;
X			root = tmp;
X			getoken();
X			root->right = expr_left_to_right_parse(strength);
X		}
X	}
X	DBUG_RETURN(root);
X}
X
XEXPR_NODE *primary_parse()
X{
X	register EXPR_NODE *root = NULL, *end_pointer, *tmp;
X	register int lpar;
X
X	DBUG_ENTER("primary_parse");
X	switch ( Token )
X	{
X	case T_LPAREN:
X		/*
X		 * it's a parenthesized expression
X		 */
X		getoken();
X		root = expr_parse();
X		if ( Token!=T_RPAREN )
X			error( "missing ')'", ACT_ERROR );
X		getoken();
X		break;
X	case T_LNOT:
X	case T_NOT:
X	case T_INCR:
X	case T_DECR:
X	case T_DOLLAR:
X		root = get_expr_node(Token);
X		getoken();
X		root->left = primary_parse();
X		break;
X	case T_SUB:
X		root = get_expr_node((char) T_UMINUS);
X		getoken();
X		root->left = primary_parse();
X		break;
X	case T_MUL:
X		root = get_expr_node((char) T_STAR);
X		getoken();
X		root->left = primary_parse();
X		break;
X	case T_AND:
X		root = get_expr_node((char) T_ADDROF);
X		getoken();
X		root->left = primary_parse();
X		break;
X	case T_ADD:
X		getoken();
X		root = primary_parse();
X		break;
X	case T_CONSTANT:
X		root = get_expr_node(Token);
X		root->left = (EXPR_NODE *) getmemory(sizeof(DATUM));
X		((DATUM *) (root->left))->ival = Value.ival;
X		getoken();
X		break;
X	case T_FUNCTION:
X		root = get_expr_node(Token);
X		root->left = (EXPR_NODE *) getmemory(sizeof(DATUM));
X		((DATUM *) (root->left))->ival = Value.ival;
X		getoken();
X		if ( Token==T_LPAREN )
X		{
X			lpar = 1;
X			getoken();
X		}
X		else
X			lpar = 0;
X		/*
X		 * Parse arguments into a list of expressions.
X		 */
X		if ( Token!=T_RPAREN && Token!=T_EOF )
X		{
X			for ( ;; )
X			{
X				tmp = get_expr_node((char) T_FUNCTION);
X				if(!root->right) {
X					root->right = end_pointer = tmp;
X				} else {
X					end_pointer->right = tmp;
X					end_pointer = tmp;
X				}
X				end_pointer->left = expr_parse();
X				if((tmp = end_pointer->left) &&
X				   (tmp->operator == T_REGEXP))
X					tmp->operator = T_REGEXP_ARG;
X				if ( Token==T_COMMA )
X					getoken();
X				else
X					break;
X			}
X		}
X		if ( lpar )
X			if( Token!=T_RPAREN )
X				error( "missing ')'", ACT_ERROR );
X			else
X				getoken();
X		break;
X	case T_REGEXP:
X	case T_STRING:
X		root = get_expr_node(Token);
X		root->left = (EXPR_NODE *) getmemory(strlen(Value.dptr) + 1);
X		strcpy((char *) root->left, Value.dptr);
X		getoken();
X		break;
X	case T_NF:
X	case T_NR:
X	case T_FS:
X	case T_RS:
X	case T_FILENAME:
X	case T_BEGIN:
X	case T_END:
X		root = get_expr_node(Token);
X		getoken();
X		break;
X	case T_VARIABLE:
X		root = get_expr_node(Token);
X		root->left = (EXPR_NODE *) Value.dptr;
X		getoken();
X		break;
X	case T_EOF:
X		break;
X	default:
X		syntaxerror();
X	}
X	/*
X	 * a "[" means it's an array reference
X	 */
X	if ( Token==T_LBRACKET )
X	{
X		tmp = get_expr_node(Token);
X		tmp->left = root;
X		root = tmp;
X		getoken();
X		root->right = expr_parse();
X		if ( Token!=T_RBRACKET )
X			error( "missing ']'", ACT_ERROR );
X		getoken();
X	}
X
X	if ( Token==T_INCR || Token==T_DECR )
X	{
X		tmp = get_expr_node((char)
X				((Token==T_INCR) ? T_POSTINCR : T_POSTDECR));
X		tmp->left = root;
X		root = tmp;
X	}
X	DBUG_RETURN(root);
X}
X
Xvoid syntaxerror()
X{
X	DBUG_ENTER("syntaxerror");
X	error( "syntax error", ACT_ERROR );
X	DBUG_VOID_RETURN;
X}
