8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 14:03:02 +01:00
firebird-mirror/src/dudley/expr.cpp
2003-09-10 17:52:12 +00:00

1158 lines
26 KiB
C++

/*
* PROGRAM: JRD Command Oriented Query Language
* MODULE: expr.c
* DESCRIPTION: Expression parser
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include <setjmp.h>
#include "../jrd/gds.h"
#include "../dudley/ddl.h"
#include "../dudley/parse.h"
#include "../jrd/acl.h"
#include "../jrd/intl.h"
#include "../dudley/ddl_proto.h"
#include "../dudley/expr_proto.h"
#include "../dudley/lex_proto.h"
#include "../dudley/parse_proto.h"
extern jmp_buf parse_env;
static CON make_numeric_constant(TEXT *, USHORT);
static DUDLEY_NOD parse_add(USHORT *, bool *);
static DUDLEY_NOD parse_and(USHORT *);
static DUDLEY_NOD parse_field(void);
static DUDLEY_NOD parse_from(USHORT *, bool *);
static DUDLEY_NOD parse_function(void);
static DUDLEY_NOD parse_gen_id(void);
static CON parse_literal(void);
static void parse_matching_paren(void);
static DUDLEY_NOD parse_multiply(USHORT *, bool *);
static DUDLEY_NOD parse_not(USHORT *);
static DUDLEY_NOD parse_primitive_value(USHORT *, bool *);
static DUDLEY_CTX parse_relation(void);
static DUDLEY_NOD parse_relational(USHORT *);
static DUDLEY_NOD parse_sort(void);
static DUDLEY_NOD parse_statistical(void);
static void parse_terminating_parens(USHORT *, USHORT *);
static struct nod_types {
enum kwwords nod_t_keyword;
enum nod_t nod_t_node;
} statisticals[] = {
{ KW_MAX, nod_max },
{ KW_MIN, nod_min },
{ KW_COUNT, nod_count },
{ KW_AVERAGE, nod_average },
{ KW_TOTAL, nod_total }
};
static enum nod_t relationals[] = {
nod_eql, nod_neq, nod_leq, nod_lss, nod_gtr, nod_geq, nod_containing,
nod_starts, nod_missing, nod_between, nod_sleuth, nod_matches,
nod_and, nod_or, nod_not, nod_any, nod_unique, (enum nod_t) 0
};
DUDLEY_NOD EXPR_boolean(USHORT * paren_count)
{
/**************************************
*
* E X P R _ b o o l e a n
*
**************************************
*
* Functional description
* Parse a general boolean expression. By precedence, handle an OR
* here.
*
**************************************/
DUDLEY_NOD expr, node;
USHORT local_count;
if (!paren_count) {
local_count = 0;
paren_count = &local_count;
}
expr = parse_and(paren_count);
if (!MATCH(KW_OR)) {
parse_terminating_parens(paren_count, &local_count);
return expr;
}
node = SYNTAX_NODE(nod_or, 2);
node->nod_arg[0] = expr;
node->nod_arg[1] = EXPR_boolean(paren_count);
parse_terminating_parens(paren_count, &local_count);
return node;
}
DUDLEY_NOD EXPR_rse(bool view_flag)
{
/**************************************
*
* E X P R _ r s e
*
**************************************
*
* Functional description
* Parse a record selection expression.
*
**************************************/
DUDLEY_NOD node, boolean, field_name, a_boolean;
LLS stack;
DUDLEY_CTX context;
SYM field_sym;
node = SYNTAX_NODE(nod_rse, s_rse_count);
stack = NULL;
LEX_real();
if (MATCH(KW_ALL))
LEX_real();
if (MATCH(KW_FIRST))
node->nod_arg[s_rse_first] = EXPR_value(0, NULL);
while (true) {
LLS_PUSH(parse_relation(), &stack);
if (MATCH(KW_OVER)) {
for (;;) {
if (!stack->lls_next) {
PARSE_error(234, NULL, NULL); /* msg 234: OVER can only be used in CROSS expressions */
}
boolean = SYNTAX_NODE(nod_eql, 2);
field_sym = PARSE_symbol(tok_ident);
field_name = SYNTAX_NODE(nod_field_name, 2);
context = (DUDLEY_CTX) stack->lls_object;
field_name->nod_arg[0] = (DUDLEY_NOD) context->ctx_name;
field_name->nod_arg[1] = (DUDLEY_NOD) field_sym;
boolean->nod_arg[0] = field_name;
field_name = SYNTAX_NODE(nod_over, 2);
field_name->nod_arg[0] = (DUDLEY_NOD) context->ctx_name;
field_name->nod_arg[1] = (DUDLEY_NOD) field_sym;
boolean->nod_arg[1] = field_name;
if (node->nod_arg[s_rse_boolean]) {
a_boolean = SYNTAX_NODE(nod_and, 2);
a_boolean->nod_arg[0] = boolean;
a_boolean->nod_arg[1] = node->nod_arg[s_rse_boolean];
node->nod_arg[s_rse_boolean] = a_boolean;
}
else
node->nod_arg[s_rse_boolean] = boolean;
if (!MATCH(KW_COMMA))
break;
}
}
if (!MATCH(KW_CROSS))
break;
}
node->nod_arg[s_rse_contexts] = (DUDLEY_NOD) stack;
/* Pick up various other clauses */
if (MATCH(KW_WITH))
if (boolean = EXPR_boolean(0)) {
if (node->nod_arg[s_rse_boolean]) {
a_boolean = SYNTAX_NODE(nod_and, 2);
a_boolean->nod_arg[0] = boolean;
a_boolean->nod_arg[1] = node->nod_arg[s_rse_boolean];
node->nod_arg[s_rse_boolean] = a_boolean;
}
else
node->nod_arg[s_rse_boolean] = boolean;
}
if (MATCH(KW_SORTED)) {
if (view_flag)
PARSE_error(319, NULL, NULL); /* msg 234: Unexpected sort clause */
MATCH(KW_BY);
node->nod_arg[s_rse_sort] = parse_sort();
}
if (MATCH(KW_REDUCED)) {
MATCH(KW_TO);
node->nod_arg[s_rse_reduced] = parse_sort();
}
return node;
}
DUDLEY_NOD EXPR_statement(void)
{
/**************************************
*
* E X P R _ s t a t e m e n t
*
**************************************
*
* Functional description
* Parse a single trigger statement.
*
**************************************/
LLS stack;
DUDLEY_NOD node;
int number;
if (MATCH(KW_BEGIN)) {
stack = NULL;
while (!MATCH(KW_END))
LLS_PUSH(EXPR_statement(), &stack);
node = PARSE_make_list(stack);
}
else if (MATCH(KW_IF)) {
node = SYNTAX_NODE(nod_if, 3);
node->nod_arg[s_if_boolean] = EXPR_boolean(0);
MATCH(KW_THEN);
node->nod_arg[s_if_true] = EXPR_statement();
if (MATCH(KW_ELSE))
node->nod_arg[s_if_false] = EXPR_statement();
else
node->nod_count = 2;
}
else if (MATCH(KW_FOR)) {
node = SYNTAX_NODE(nod_for, 2);
node->nod_arg[s_for_rse] = EXPR_rse(false);
stack = NULL;
while (!MATCH(KW_END_FOR))
LLS_PUSH(EXPR_statement(), &stack);
node->nod_arg[s_for_action] = PARSE_make_list(stack);
}
else if (MATCH(KW_STORE)) {
node = SYNTAX_NODE(nod_store, 2);
node->nod_arg[s_store_rel] = (DUDLEY_NOD) parse_relation();
MATCH(KW_USING);
stack = NULL;
while (!MATCH(KW_END_STORE))
LLS_PUSH(EXPR_statement(), &stack);
node->nod_arg[s_store_action] = PARSE_make_list(stack);
}
else if (MATCH(KW_ABORT)) {
node = SYNTAX_NODE(nod_abort, 1);
node->nod_count = 0;
number = PARSE_number();
if (number > 255)
PARSE_error(235, NULL, NULL); /* msg 235: abort code cannot exceed 255 */
node->nod_arg[0] = (DUDLEY_NOD) (SLONG) number;
}
else if (MATCH(KW_ERASE)) {
node = SYNTAX_NODE(nod_erase, 1);
node->nod_count = 0;
node->nod_arg[0] = (DUDLEY_NOD) PARSE_symbol(tok_ident);
}
else if (MATCH(KW_MODIFY)) {
MATCH(KW_USING);
node = SYNTAX_NODE(nod_modify, 3);
node->nod_count = 0;
node->nod_arg[s_mod_old_ctx] = (DUDLEY_NOD) PARSE_symbol(tok_ident);
MATCH(KW_USING);
stack = NULL;
while (!MATCH(KW_END_MODIFY))
LLS_PUSH(EXPR_statement(), &stack);
node->nod_arg[s_mod_action] = PARSE_make_list(stack);
}
else if (MATCH(KW_POST)) {
node = SYNTAX_NODE(nod_post, 1);
node->nod_count = 1;
node->nod_arg[0] = EXPR_value(0, NULL);
}
else {
node = SYNTAX_NODE(nod_assignment, 2);
node->nod_arg[1] = parse_field();
if (!MATCH(KW_EQUALS))
PARSE_error(236, DDL_token.tok_string, NULL); /* msg 236: expected =, encountered \"%s\" */
node->nod_arg[0] = EXPR_value(0, NULL);
}
MATCH(KW_SEMI);
return node;
}
DUDLEY_NOD EXPR_value(USHORT * paren_count,
bool * bool_flag)
{
/**************************************
*
* E X P R _ v a l u e
*
**************************************
*
* Functional description
* Parse a general value expression. In practice, this means parse the
* lowest precedence operator CONCATENATE.
*
**************************************/
DUDLEY_NOD node, arg;
USHORT local_count;
bool local_flag;
if (!paren_count) {
local_count = 0;
paren_count = &local_count;
}
if (!bool_flag) {
local_flag = false;
bool_flag = &local_flag;
}
node = parse_add(paren_count, bool_flag);
while (true) {
if (!MATCH(KW_BAR)) {
parse_terminating_parens(paren_count, &local_count);
return node;
}
arg = node;
node = SYNTAX_NODE(nod_concatenate, 2);
node->nod_arg[0] = arg;
node->nod_arg[1] = parse_add(paren_count, bool_flag);
}
}
static CON make_numeric_constant( TEXT * string, USHORT length)
{
/**************************************
*
* m a k e _ n u m e r i c _ c o n s t a n t
*
**************************************
*
* Functional description
* Build a constant block for a numeric
* constant. Numeric constants are normally
* stored as long words, but especially large
* ones become text. They ought to become
* double precision, one would think, but they'd
* have to be VAX style double precision which is
* more pain than gain.
*
**************************************/
CON constant;
TEXT *p, *q, c;
USHORT scale, l, fraction;
SLONG *number;
p = string;
l = length;
constant = (CON) DDL_alloc(CON_LEN + sizeof(SLONG));
constant->con_desc.dsc_dtype = dtype_long;
constant->con_desc.dsc_length = sizeof(SLONG);
number = (SLONG *) constant->con_data;
constant->con_desc.dsc_address = (UCHAR *) number;
scale = 0;
do {
if ((c = *p++) == '.')
scale = 1;
else {
/* The right side of the following comparison had originally been:
((1 << 31) -1 ) / 10
For some reason, this doesn't work on 64-bit platforms. Its
replacement does. */
if (*number > ((SLONG) ~ (1 << 31)) / 10)
break;
*number *= 10;
*number += c - '0';
constant->con_desc.dsc_scale -= scale;
}
} while (--l);
/* if there was an overflow (indicated by the fact that we have
* some length left over), switch back to text. Do check that
* the thing is a plausible number. Also leave a space so we
* can negate it later if necessary.
*/
if (l) {
length++;
constant = (CON) DDL_alloc(CON_LEN + length);
constant->con_desc.dsc_dtype = dtype_text;
constant->con_desc.dsc_ttype = ttype_ascii;
constant->con_desc.dsc_length = length;
constant->con_desc.dsc_address = constant->con_data;
q = (TEXT *) constant->con_desc.dsc_address;
p = string;
*q++ = ' ';
fraction = 0;
for (l = 1; l < length; p++, l++)
if (*p >= '0' && *p <= '9')
*q++ = *p;
else if (*p == '.') {
*q++ = *p;
if (fraction)
DDL_err(237, NULL, NULL, NULL, NULL, NULL); /* msg 237: too many decimal points */
else
fraction = 1;
}
else
DDL_err(238, NULL, NULL, NULL, NULL, NULL); /* msg 238: unrecognized character in numeric string */
}
return constant;
}
static DUDLEY_NOD parse_add(USHORT * paren_count,
bool * bool_flag)
{
/**************************************
*
* p a r s e _ a d d
*
**************************************
*
* Functional description
* Parse a general value expression. In practice, this means parse the
* lowest precedence operators, ADD and SUBTRACT.
*
**************************************/
DUDLEY_NOD node, arg;
enum nod_t operatr;
node = parse_multiply(paren_count, bool_flag);
while (true) {
if (MATCH(KW_PLUS))
operatr = nod_add;
else if (MATCH(KW_MINUS))
operatr = nod_subtract;
else
return node;
arg = node;
node = SYNTAX_NODE(operatr, 2);
node->nod_arg[0] = arg;
node->nod_arg[1] = parse_multiply(paren_count, bool_flag);
}
}
static DUDLEY_NOD parse_and( USHORT * paren_count)
{
/**************************************
*
* p a r s e _ a n d
*
**************************************
*
* Functional description
* Parse an AND expression.
*
**************************************/
DUDLEY_NOD expr, node;
expr = parse_not(paren_count);
if (!MATCH(KW_AND))
return expr;
node = SYNTAX_NODE(nod_and, 2);
node->nod_arg[0] = expr;
node->nod_arg[1] = parse_and(paren_count);
return node;
}
static DUDLEY_NOD parse_field(void)
{
/**************************************
*
* p a r s e _ f i e l d
*
**************************************
*
* Functional description
* Parse a qualified field name.
*
**************************************/
DUDLEY_NOD field, array;
LLS stack;
stack = NULL;
while (true) {
LEX_real();
LLS_PUSH(PARSE_symbol(tok_ident), &stack);
if (!MATCH(KW_DOT))
break;
}
field = PARSE_make_list(stack);
field->nod_type = nod_field_name;
if (!MATCH(KW_L_BRCKET))
return field;
/* Parse an array reference */
stack = NULL;
for (;;) {
LLS_PUSH(EXPR_value(0, NULL), &stack);
if (MATCH(KW_R_BRCKET))
break;
if (!MATCH(KW_COMMA))
PARSE_error(317, DDL_token.tok_string, NULL); /* msg 317, expected comma or right bracket, encountered \"%s\" */
}
array = SYNTAX_NODE(nod_index, 2);
array->nod_arg[0] = field;
array->nod_arg[1] = PARSE_make_list(stack);
return array;
}
static DUDLEY_NOD parse_from(USHORT * paren_count,
bool * bool_flag)
{
/**************************************
*
* p a r s e _ f r o m
*
**************************************
*
* Functional description
* Parse either an explicit or implicit FIRST ... FROM statement.
*
**************************************/
DUDLEY_NOD node, value;
if (MATCH(KW_FIRST)) {
value = parse_primitive_value(0, NULL);
if (!MATCH(KW_FROM))
PARSE_error(239, DDL_token.tok_string, NULL);
/* msg 239: expected FROM rse clause, encountered \"%s\" */
}
else {
value = parse_primitive_value(paren_count, bool_flag);
if (!MATCH(KW_FROM))
return value;
}
node = SYNTAX_NODE(nod_from, s_stt_count);
node->nod_arg[s_stt_value] = value;
node->nod_arg[s_stt_rse] = EXPR_rse(false);
if (MATCH(KW_ELSE))
node->nod_arg[s_stt_default] = EXPR_value(0, NULL);
return node;
}
static DUDLEY_NOD parse_function(void)
{
/**************************************
*
* p a r s e _ f u n c t i o n
*
**************************************
*
* Functional description
* Parse a function reference. If not a function, return NULL.
*
**************************************/
SYM symbol;
DUDLEY_NOD node;
LLS stack;
/* Look for symbol of type function. If we don't find it, give up */
for (symbol = DDL_token.tok_symbol; symbol; symbol = symbol->sym_homonym)
if (symbol->sym_type == SYM_function)
break;
if (!symbol)
return NULL;
node = SYNTAX_NODE(nod_function, 3);
node->nod_count = 1;
node->nod_arg[1] = (DUDLEY_NOD) PARSE_symbol(tok_ident);
node->nod_arg[2] = (DUDLEY_NOD) symbol->sym_object;
stack = NULL;
if (MATCH(KW_LEFT_PAREN) && !MATCH(KW_RIGHT_PAREN))
for (;;) {
LLS_PUSH(EXPR_value(0, NULL), &stack);
if (MATCH(KW_RIGHT_PAREN))
break;
if (!MATCH(KW_COMMA))
PARSE_error(240, DDL_token.tok_string, NULL);
/* msg 240: expected comma or right parenthesis, encountered \"%s\" */
}
node->nod_arg[0] = PARSE_make_list(stack);
return node;
}
static DUDLEY_NOD parse_gen_id(void)
{
/**************************************
*
* p a r s e _ g e n _ i d
*
**************************************
*
* Functional description
* Parse GEN_ID expression. Syntax is:
*
* GEN_ID (<relation_name>, <value>)
*
**************************************/
DUDLEY_NOD node;
LEX_token();
if (!MATCH(KW_LEFT_PAREN))
PARSE_error(241, DDL_token.tok_string, NULL); /* msg 241: expected left parenthesis, encountered \"%s\" */
node = SYNTAX_NODE(nod_gen_id, 2);
node->nod_count = 1;
node->nod_arg[1] = (DUDLEY_NOD) PARSE_symbol(tok_ident);
MATCH(KW_COMMA);
node->nod_arg[0] = EXPR_value(0, NULL);
parse_matching_paren();
return node;
}
static CON parse_literal(void)
{
/**************************************
*
* p a r s e _ l i t e r a l
*
**************************************
*
* Functional description
* Parse a literal expression.
*
**************************************/
CON constant;
USHORT l;
TEXT *p, *q;
q = DDL_token.tok_string;
l = DDL_token.tok_length;
if (DDL_token.tok_type == tok_quoted) {
q++;
l -= 2;
constant = (CON) DDL_alloc(CON_LEN + l);
constant->con_desc.dsc_dtype = dtype_text;
constant->con_desc.dsc_ttype = ttype_ascii;
p = (TEXT *) constant->con_data;
constant->con_desc.dsc_address = (UCHAR *) p;
if (constant->con_desc.dsc_length = l)
do
*p++ = *q++;
while (--l);
}
else if (DDL_token.tok_type == tok_number) {
constant = make_numeric_constant(DDL_token.tok_string,
DDL_token.tok_length);
}
else
PARSE_error(242, DDL_token.tok_string, NULL); /* msg 242: expected value expression, encountered \"%s\" */
LEX_token();
return constant;
}
static void parse_matching_paren(void)
{
/**************************************
*
* p a r s e _ m a t c h i n g _ p a r e n
*
**************************************
*
* Functional description
* Check for balancing parenthesis. If missing, barf.
*
**************************************/
if (!MATCH(KW_RIGHT_PAREN))
PARSE_error(243, DDL_token.tok_string, NULL); /* msg 243: expected right parenthesis, encountered \"%s\" */
}
static DUDLEY_NOD parse_multiply(USHORT * paren_count,
bool * bool_flag)
{
/**************************************
*
* p a r s e _ m u l t i p l y
*
**************************************
*
* Functional description
* Parse the operators * and /.
*
**************************************/
DUDLEY_NOD node, arg;
enum nod_t operatr;
node = parse_from(paren_count, bool_flag);
while (true) {
if (MATCH(KW_ASTERISK))
operatr = nod_multiply;
else if (MATCH(KW_SLASH))
operatr = nod_divide;
else
return node;
arg = node;
node = SYNTAX_NODE(operatr, 2);
node->nod_arg[0] = arg;
node->nod_arg[1] = parse_from(paren_count, bool_flag);
}
}
static DUDLEY_NOD parse_not( USHORT * paren_count)
{
/**************************************
*
* p a r s e _ n o t
*
**************************************
*
* Functional description
* Parse a prefix NOT expression.
*
**************************************/
DUDLEY_NOD node;
LEX_real();
if (!MATCH(KW_NOT))
return parse_relational(paren_count);
node = SYNTAX_NODE(nod_not, 1);
node->nod_arg[0] = parse_not(paren_count);
return node;
}
static DUDLEY_NOD parse_primitive_value(USHORT * paren_count,
bool * bool_flag)
{
/**************************************
*
* p a r s e _ p r i m i t i v e _ v a l u e
*
**************************************
*
* Functional description
* Pick up a value expression. This may be either a field reference
* or a constant value.
*
**************************************/
DUDLEY_NOD node, sub;
CON constant;
TEXT *p;
USHORT local_count;
if (!paren_count) {
local_count = 0;
paren_count = &local_count;
}
switch (PARSE_keyword()) {
case KW_LEFT_PAREN:
LEX_token();
(*paren_count)++;
if (bool_flag && *bool_flag)
node = EXPR_boolean(paren_count);
else
node = EXPR_value(paren_count, bool_flag);
parse_matching_paren();
(*paren_count)--;
break;
case KW_MINUS:
LEX_token();
sub = parse_primitive_value(paren_count, NULL);
if (sub->nod_type == nod_literal) {
constant = (CON) sub->nod_arg[0];
p = (TEXT *) constant->con_desc.dsc_address;
switch (constant->con_desc.dsc_dtype) {
case dtype_long:
*(SLONG *) p = -*(SLONG *) p;
return sub;
case dtype_text:
*p = '-';
return sub;
}
}
node = SYNTAX_NODE(nod_negate, 1);
node->nod_arg[0] = sub;
break;
case KW_COUNT:
case KW_MAX:
case KW_MIN:
case KW_AVERAGE:
case KW_TOTAL:
node = parse_statistical();
break;
case KW_NULL:
LEX_token();
node = SYNTAX_NODE(nod_null, 0);
break;
case KW_USER_NAME:
LEX_token();
node = SYNTAX_NODE(nod_user_name, 0);
break;
case KW_GEN_ID:
node = parse_gen_id();
break;
case KW_UPPERCASE:
LEX_token();
sub = parse_primitive_value(0, NULL);
node = SYNTAX_NODE(nod_uppercase, 1);
node->nod_arg[0] = sub;
break;
default:
if (DDL_token.tok_type == tok_ident) {
if (!(node = parse_function()))
node = parse_field();
break;
}
node = SYNTAX_NODE(nod_literal, 1);
node->nod_arg[0] = (DUDLEY_NOD) parse_literal();
}
return node;
}
static DUDLEY_CTX parse_relation(void)
{
/**************************************
*
* p a r s e _ r e l a t i o n
*
**************************************
*
* Functional description
* Parse a relation expression. Syntax is:
*
* [ <context_variable> IN ] <relation>
*
**************************************/
SYM symbol;
DUDLEY_CTX context;
context = (DUDLEY_CTX) DDL_alloc(CTX_LEN);
context->ctx_name = symbol = PARSE_symbol(tok_ident);
symbol->sym_type = SYM_context;
symbol->sym_object = context;
if (!MATCH(KW_IN))
PARSE_error(244, DDL_token.tok_string, NULL); /* msg 244: expected IN, encountered \"%s\" */
context->ctx_relation = PARSE_relation();
return context;
}
static DUDLEY_NOD parse_relational( USHORT * paren_count)
{
/**************************************
*
* p a r s e _ r e l a t i o n a l
*
**************************************
*
* Functional description
* Parse a relational expression.
*
**************************************/
DUDLEY_NOD node, expr1, expr2, or_node;
bool negation;
enum nod_t operatr, *rel_ops;
bool local_flag = true;
if (MATCH(KW_ANY)) {
node = SYNTAX_NODE(nod_any, 1);
node->nod_arg[0] = EXPR_rse(false);
return node;
}
if (MATCH(KW_UNIQUE)) {
node = SYNTAX_NODE(nod_unique, 1);
node->nod_arg[0] = EXPR_rse(false);
return node;
}
expr1 = EXPR_value(paren_count, &local_flag);
if (KEYWORD(KW_RIGHT_PAREN))
return expr1;
negation = false;
node = NULL;
LEX_real();
if (MATCH(KW_NOT)) {
negation = true;
LEX_real();
}
switch (PARSE_keyword()) {
case KW_EQUALS:
case KW_EQ:
operatr = (negation) ? nod_neq : nod_eql;
negation = false;
break;
case KW_NE:
operatr = (negation) ? nod_eql : nod_neq;
negation = false;
break;
case KW_GT:
operatr = (negation) ? nod_leq : nod_gtr;
negation = false;
break;
case KW_GE:
operatr = (negation) ? nod_lss : nod_geq;
negation = false;
break;
case KW_LE:
operatr = (negation) ? nod_gtr : nod_leq;
negation = false;
break;
case KW_LT:
operatr = (negation) ? nod_geq : nod_lss;
negation = false;
break;
case KW_CONTAINING:
operatr = nod_containing;
break;
case KW_MATCHES:
LEX_token();
expr2 = EXPR_value(0, NULL);
if (MATCH(KW_USING)) {
operatr = nod_sleuth;
node = SYNTAX_NODE(operatr, 3);
node->nod_arg[2] = EXPR_value(0, NULL);
}
else {
operatr = nod_matches;
node = SYNTAX_NODE(operatr, 2);
}
node->nod_arg[0] = expr1;
node->nod_arg[1] = expr2;
break;
case KW_STARTS:
LEX_token();
MATCH(KW_WITH);
node = SYNTAX_NODE(nod_starts, 2);
node->nod_arg[0] = expr1;
node->nod_arg[1] = EXPR_value(0, NULL);
break;
case KW_MISSING:
LEX_token();
node = SYNTAX_NODE(nod_missing, 1);
node->nod_arg[0] = expr1;
break;
case KW_BETWEEN:
LEX_token();
node = SYNTAX_NODE(nod_between, 3);
node->nod_arg[0] = expr1;
node->nod_arg[1] = EXPR_value(0, NULL);
MATCH(KW_AND);
node->nod_arg[2] = EXPR_value(0, NULL);
break;
default:
for (rel_ops = relationals; *rel_ops != (enum nod_t) 0; rel_ops++)
if (expr1->nod_type == *rel_ops)
return expr1;
PARSE_error(245, DDL_token.tok_string, NULL); /* msg 245: expected relational operator, encountered \"%s\" */
}
/* If we haven't already built a node, it must be an ordinary binary operator.
Build it. */
if (!node) {
LEX_token();
node = SYNTAX_NODE(operatr, 2);
node->nod_arg[0] = expr1;
node->nod_arg[1] = EXPR_value(paren_count, &local_flag);
}
/* If a negation remains to be handled, zap the node under a NOT. */
if (negation) {
expr1 = SYNTAX_NODE(nod_not, 1);
expr1->nod_arg[0] = node;
node = expr1;
}
/* If the node isn't an equality, we've done. Since equalities can be structured
as implicit ORs, build them here. */
if (operatr != nod_eql)
return node;
/* We have an equality operation, which can take a number of values. Generate
implicit ORs */
while (MATCH(KW_COMMA)) {
MATCH(KW_OR);
or_node = SYNTAX_NODE(nod_or, 2);
or_node->nod_arg[0] = node;
or_node->nod_arg[1] = node = SYNTAX_NODE(nod_eql, 2);
node->nod_arg[0] = expr1;
node->nod_arg[1] = EXPR_value(paren_count, &local_flag);
node = or_node;
}
return node;
}
static DUDLEY_NOD parse_sort(void)
{
/**************************************
*
* p a r s e _ s o r t
*
**************************************
*
* Functional description
* Parse a sort list.
*
**************************************/
LLS stack;
SSHORT direction;
direction = 0;
stack = NULL;
while (true) {
LEX_real();
if (MATCH(KW_ASCENDING))
direction = 0;
else if (MATCH(KW_DESCENDING))
direction = 1;
LLS_PUSH(EXPR_value(0, NULL), &stack);
LLS_PUSH((SLONG) direction, &stack);
if (!MATCH(KW_COMMA))
break;
}
return PARSE_make_list(stack);
}
static DUDLEY_NOD parse_statistical(void)
{
/**************************************
*
* p a r s e _ s t a t i s t i c a l
*
**************************************
*
* Functional description
* Parse statistical expression.
*
**************************************/
struct nod_types *types;
DUDLEY_NOD node;
enum kwwords keyword;
keyword = PARSE_keyword();
LEX_token();
for (types = statisticals;; types++)
if (types->nod_t_keyword == keyword)
break;
node = SYNTAX_NODE(types->nod_t_node, s_stt_count);
if (node->nod_type != nod_count)
node->nod_arg[s_stt_value] = EXPR_value(0, NULL);
if (!MATCH(KW_OF))
PARSE_error(246, DDL_token.tok_string, NULL); /* msg 246: expected OF, encountered \"%s\" */
node->nod_arg[s_stt_rse] = EXPR_rse(false);
return node;
}
static void parse_terminating_parens(USHORT * paren_count,
USHORT * local_count)
{
/**************************************
*
* p a r s e _ t e r m i n a t i n g _ p a r e n s
*
**************************************
*
* Functional description
* Check for balancing parenthesis. If missing, barf.
*
**************************************/
if (*paren_count && paren_count == local_count)
do
parse_matching_paren();
while (--(*paren_count));
}