8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-29 06:43:03 +01:00
firebird-mirror/src/dudley/expr.cpp

1156 lines
27 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Command Oriented Query Language
2003-10-05 08:42:03 +02:00
* MODULE: expr.cpp
2001-05-23 15:26:42 +02:00
* 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"
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
#include "../jrd/y_ref.h"
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#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"
static CON make_numeric_constant(TEXT *, USHORT);
2003-09-10 19:52:12 +02:00
static DUDLEY_NOD parse_add(USHORT *, bool *);
static DUDLEY_NOD parse_and(USHORT *);
static DUDLEY_NOD parse_field(void);
2003-09-10 19:52:12 +02:00
static DUDLEY_NOD parse_from(USHORT *, bool *);
static DUDLEY_NOD parse_function(void);
static DUDLEY_NOD parse_gen_id(void);
2001-05-23 15:26:42 +02:00
static CON parse_literal(void);
2002-07-06 07:32:02 +02:00
static void parse_matching_paren(void);
2003-09-10 19:52:12 +02:00
static DUDLEY_NOD parse_multiply(USHORT *, bool *);
static DUDLEY_NOD parse_not(USHORT *);
2003-09-10 19:52:12 +02:00
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);
2002-07-06 07:32:02 +02:00
static void parse_terminating_parens(USHORT *, USHORT *);
2001-05-23 15:26:42 +02:00
static struct nod_types {
enum kwwords nod_t_keyword;
enum nod_t nod_t_node;
} statisticals[] = {
2002-04-04 07:36:37 +02:00
{ KW_MAX, nod_max },
{ KW_MIN, nod_min },
{ KW_COUNT, nod_count },
{ KW_AVERAGE, nod_average },
{ KW_TOTAL, nod_total }
};
2001-05-23 15:26:42 +02:00
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)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
USHORT local_count;
if (!paren_count) {
local_count = 0;
paren_count = &local_count;
}
expr = parse_and(paren_count);
if (!PARSE_match(KW_OR)) {
2001-05-23 15:26:42 +02:00
parse_terminating_parens(paren_count, &local_count);
return expr;
}
node = PARSE_make_node(nod_or, 2);
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = expr;
node->nod_arg[1] = EXPR_boolean(paren_count);
parse_terminating_parens(paren_count, &local_count);
return node;
}
2003-09-10 19:52:12 +02:00
DUDLEY_NOD EXPR_rse(bool view_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* E X P R _ r s e
*
**************************************
*
* Functional description
* Parse a record selection expression.
*
**************************************/
2003-02-05 16:43:59 +01:00
DUDLEY_NOD node, boolean, field_name, a_boolean;
LLS stack;
DUDLEY_CTX context;
2001-05-23 15:26:42 +02:00
SYM field_sym;
node = PARSE_make_node(nod_rse, s_rse_count);
2001-05-23 15:26:42 +02:00
stack = NULL;
LEX_real();
if (PARSE_match(KW_ALL))
2001-05-23 15:26:42 +02:00
LEX_real();
if (PARSE_match(KW_FIRST))
2003-09-10 19:52:12 +02:00
node->nod_arg[s_rse_first] = EXPR_value(0, NULL);
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
LLS_PUSH((DUDLEY_NOD) parse_relation(), &stack);
if (PARSE_match(KW_OVER)) {
2001-05-23 15:26:42 +02:00
for (;;) {
if (!stack->lls_next) {
PARSE_error(234, NULL, NULL); /* msg 234: OVER can only be used in CROSS expressions */
}
boolean = PARSE_make_node(nod_eql, 2);
2001-05-23 15:26:42 +02:00
field_sym = PARSE_symbol(tok_ident);
field_name = PARSE_make_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;
2001-05-23 15:26:42 +02:00
boolean->nod_arg[0] = field_name;
field_name = PARSE_make_node(nod_over, 2);
field_name->nod_arg[0] = (DUDLEY_NOD) context->ctx_name;
field_name->nod_arg[1] = (DUDLEY_NOD) field_sym;
2001-05-23 15:26:42 +02:00
boolean->nod_arg[1] = field_name;
if (node->nod_arg[s_rse_boolean]) {
a_boolean = PARSE_make_node(nod_and, 2);
2001-05-23 15:26:42 +02:00
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 (!PARSE_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
}
if (!PARSE_match(KW_CROSS))
2001-05-23 15:26:42 +02:00
break;
}
node->nod_arg[s_rse_contexts] = (DUDLEY_NOD) stack;
2001-05-23 15:26:42 +02:00
/* Pick up various other clauses */
if (PARSE_match(KW_WITH))
2001-05-23 15:26:42 +02:00
if (boolean = EXPR_boolean(0)) {
if (node->nod_arg[s_rse_boolean]) {
a_boolean = PARSE_make_node(nod_and, 2);
2001-05-23 15:26:42 +02:00
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 (PARSE_match(KW_SORTED)) {
2001-05-23 15:26:42 +02:00
if (view_flag)
PARSE_error(319, NULL, NULL); /* msg 234: Unexpected sort clause */
PARSE_match(KW_BY);
2001-05-23 15:26:42 +02:00
node->nod_arg[s_rse_sort] = parse_sort();
}
if (PARSE_match(KW_REDUCED)) {
PARSE_match(KW_TO);
2001-05-23 15:26:42 +02:00
node->nod_arg[s_rse_reduced] = parse_sort();
}
return node;
}
DUDLEY_NOD EXPR_statement(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* E X P R _ s t a t e m e n t
*
**************************************
*
* Functional description
* Parse a single trigger statement.
*
**************************************/
LLS stack;
2003-02-05 16:43:59 +01:00
DUDLEY_NOD node;
2001-05-23 15:26:42 +02:00
int number;
if (PARSE_match(KW_BEGIN)) {
2001-05-23 15:26:42 +02:00
stack = NULL;
while (!PARSE_match(KW_END))
2001-05-23 15:26:42 +02:00
LLS_PUSH(EXPR_statement(), &stack);
node = PARSE_make_list(stack);
}
else if (PARSE_match(KW_IF)) {
node = PARSE_make_node(nod_if, 3);
2001-05-23 15:26:42 +02:00
node->nod_arg[s_if_boolean] = EXPR_boolean(0);
PARSE_match(KW_THEN);
2001-05-23 15:26:42 +02:00
node->nod_arg[s_if_true] = EXPR_statement();
if (PARSE_match(KW_ELSE))
2001-05-23 15:26:42 +02:00
node->nod_arg[s_if_false] = EXPR_statement();
else
node->nod_count = 2;
}
else if (PARSE_match(KW_FOR)) {
node = PARSE_make_node(nod_for, 2);
2003-09-10 19:52:12 +02:00
node->nod_arg[s_for_rse] = EXPR_rse(false);
2001-05-23 15:26:42 +02:00
stack = NULL;
while (!PARSE_match(KW_END_FOR))
2001-05-23 15:26:42 +02:00
LLS_PUSH(EXPR_statement(), &stack);
node->nod_arg[s_for_action] = PARSE_make_list(stack);
}
else if (PARSE_match(KW_STORE)) {
node = PARSE_make_node(nod_store, 2);
node->nod_arg[s_store_rel] = (DUDLEY_NOD) parse_relation();
PARSE_match(KW_USING);
2001-05-23 15:26:42 +02:00
stack = NULL;
while (!PARSE_match(KW_END_STORE))
2001-05-23 15:26:42 +02:00
LLS_PUSH(EXPR_statement(), &stack);
node->nod_arg[s_store_action] = PARSE_make_list(stack);
}
else if (PARSE_match(KW_ABORT)) {
node = PARSE_make_node(nod_abort, 1);
2001-05-23 15:26:42 +02:00
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;
2001-05-23 15:26:42 +02:00
}
else if (PARSE_match(KW_ERASE)) {
node = PARSE_make_node(nod_erase, 1);
2001-05-23 15:26:42 +02:00
node->nod_count = 0;
node->nod_arg[0] = (DUDLEY_NOD) PARSE_symbol(tok_ident);
2001-05-23 15:26:42 +02:00
}
else if (PARSE_match(KW_MODIFY)) {
PARSE_match(KW_USING);
node = PARSE_make_node(nod_modify, 3);
2001-05-23 15:26:42 +02:00
node->nod_count = 0;
node->nod_arg[s_mod_old_ctx] = (DUDLEY_NOD) PARSE_symbol(tok_ident);
PARSE_match(KW_USING);
2001-05-23 15:26:42 +02:00
stack = NULL;
while (!PARSE_match(KW_END_MODIFY))
2001-05-23 15:26:42 +02:00
LLS_PUSH(EXPR_statement(), &stack);
node->nod_arg[s_mod_action] = PARSE_make_list(stack);
}
else if (PARSE_match(KW_POST)) {
node = PARSE_make_node(nod_post, 1);
2001-05-23 15:26:42 +02:00
node->nod_count = 1;
2003-09-10 19:52:12 +02:00
node->nod_arg[0] = EXPR_value(0, NULL);
2001-05-23 15:26:42 +02:00
}
else {
node = PARSE_make_node(nod_assignment, 2);
2001-05-23 15:26:42 +02:00
node->nod_arg[1] = parse_field();
if (!PARSE_match(KW_EQUALS))
2001-05-23 15:26:42 +02:00
PARSE_error(236, DDL_token.tok_string, NULL); /* msg 236: expected =, encountered \"%s\" */
2003-09-10 19:52:12 +02:00
node->nod_arg[0] = EXPR_value(0, NULL);
2001-05-23 15:26:42 +02:00
}
PARSE_match(KW_SEMI);
2001-05-23 15:26:42 +02:00
return node;
}
2003-09-10 19:52:12 +02:00
DUDLEY_NOD EXPR_value(USHORT * paren_count,
bool * bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2003-09-10 19:52:12 +02:00
USHORT local_count;
bool local_flag;
2001-05-23 15:26:42 +02:00
if (!paren_count) {
local_count = 0;
paren_count = &local_count;
}
if (!bool_flag) {
2003-09-10 19:52:12 +02:00
local_flag = false;
2001-05-23 15:26:42 +02:00
bool_flag = &local_flag;
}
node = parse_add(paren_count, bool_flag);
2003-09-10 19:52:12 +02:00
while (true) {
if (!PARSE_match(KW_BAR)) {
2001-05-23 15:26:42 +02:00
parse_terminating_parens(paren_count, &local_count);
return node;
}
arg = node;
node = PARSE_make_node(nod_concatenate, 2);
2001-05-23 15:26:42 +02:00
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;
2003-09-30 12:39:11 +02:00
constant = (CON) DDL_alloc(sizeof(con) + sizeof(SLONG));
2001-05-23 15:26:42 +02:00
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*) (IPTR) number;
2001-05-23 15:26:42 +02:00
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++;
2003-09-30 12:39:11 +02:00
constant = (CON) DDL_alloc(sizeof(con) + length);
2001-05-23 15:26:42 +02:00
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;
}
2003-09-10 19:52:12 +02:00
static DUDLEY_NOD parse_add(USHORT * paren_count,
bool * bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-07-12 07:46:06 +02:00
enum nod_t operatr;
2001-05-23 15:26:42 +02:00
node = parse_multiply(paren_count, bool_flag);
2003-09-10 19:52:12 +02:00
while (true) {
if (PARSE_match(KW_PLUS))
2001-07-12 07:46:06 +02:00
operatr = nod_add;
else if (PARSE_match(KW_MINUS))
2001-07-12 07:46:06 +02:00
operatr = nod_subtract;
2001-05-23 15:26:42 +02:00
else
return node;
arg = node;
node = PARSE_make_node(operatr, 2);
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = arg;
node->nod_arg[1] = parse_multiply(paren_count, bool_flag);
}
}
static DUDLEY_NOD parse_and( USHORT * paren_count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ a n d
*
**************************************
*
* Functional description
* Parse an AND expression.
*
**************************************/
DUDLEY_NOD expr, node;
2001-05-23 15:26:42 +02:00
expr = parse_not(paren_count);
if (!PARSE_match(KW_AND))
2001-05-23 15:26:42 +02:00
return expr;
node = PARSE_make_node(nod_and, 2);
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = expr;
node->nod_arg[1] = parse_and(paren_count);
return node;
}
static DUDLEY_NOD parse_field(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ f i e l d
*
**************************************
*
* Functional description
* Parse a qualified field name.
*
**************************************/
DUDLEY_NOD field, array;
2001-05-23 15:26:42 +02:00
LLS stack;
stack = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
LEX_real();
LLS_PUSH((DUDLEY_NOD) PARSE_symbol(tok_ident), &stack);
if (!PARSE_match(KW_DOT))
2001-05-23 15:26:42 +02:00
break;
}
field = PARSE_make_list(stack);
field->nod_type = nod_field_name;
if (!PARSE_match(KW_L_BRCKET))
2001-05-23 15:26:42 +02:00
return field;
/* Parse an array reference */
stack = NULL;
for (;;) {
2003-09-10 19:52:12 +02:00
LLS_PUSH(EXPR_value(0, NULL), &stack);
if (PARSE_match(KW_R_BRCKET))
2001-05-23 15:26:42 +02:00
break;
if (!PARSE_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
PARSE_error(317, DDL_token.tok_string, NULL); /* msg 317, expected comma or right bracket, encountered \"%s\" */
}
array = PARSE_make_node(nod_index, 2);
2001-05-23 15:26:42 +02:00
array->nod_arg[0] = field;
array->nod_arg[1] = PARSE_make_list(stack);
return array;
}
2003-09-10 19:52:12 +02:00
static DUDLEY_NOD parse_from(USHORT * paren_count,
bool * bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ f r o m
*
**************************************
*
* Functional description
* Parse either an explicit or implicit FIRST ... FROM statement.
*
**************************************/
DUDLEY_NOD node, value;
2001-05-23 15:26:42 +02:00
if (PARSE_match(KW_FIRST)) {
2003-09-10 19:52:12 +02:00
value = parse_primitive_value(0, NULL);
if (!PARSE_match(KW_FROM))
2001-05-23 15:26:42 +02:00
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 (!PARSE_match(KW_FROM))
2001-05-23 15:26:42 +02:00
return value;
}
node = PARSE_make_node(nod_from, s_stt_count);
2001-05-23 15:26:42 +02:00
node->nod_arg[s_stt_value] = value;
2003-09-10 19:52:12 +02:00
node->nod_arg[s_stt_rse] = EXPR_rse(false);
2001-05-23 15:26:42 +02:00
if (PARSE_match(KW_ELSE))
2003-09-10 19:52:12 +02:00
node->nod_arg[s_stt_default] = EXPR_value(0, NULL);
2001-05-23 15:26:42 +02:00
return node;
}
static DUDLEY_NOD parse_function(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
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 = PARSE_make_node(nod_function, 3);
2001-05-23 15:26:42 +02:00
node->nod_count = 1;
node->nod_arg[1] = (DUDLEY_NOD) PARSE_symbol(tok_ident);
node->nod_arg[2] = (DUDLEY_NOD) symbol->sym_object;
2001-05-23 15:26:42 +02:00
stack = NULL;
if (PARSE_match(KW_LEFT_PAREN) && !PARSE_match(KW_RIGHT_PAREN))
2001-05-23 15:26:42 +02:00
for (;;) {
2003-09-10 19:52:12 +02:00
LLS_PUSH(EXPR_value(0, NULL), &stack);
if (PARSE_match(KW_RIGHT_PAREN))
2001-05-23 15:26:42 +02:00
break;
if (!PARSE_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
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)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
LEX_token();
if (!PARSE_match(KW_LEFT_PAREN))
2001-05-23 15:26:42 +02:00
PARSE_error(241, DDL_token.tok_string, NULL); /* msg 241: expected left parenthesis, encountered \"%s\" */
node = PARSE_make_node(nod_gen_id, 2);
2001-05-23 15:26:42 +02:00
node->nod_count = 1;
node->nod_arg[1] = (DUDLEY_NOD) PARSE_symbol(tok_ident);
PARSE_match(KW_COMMA);
2003-09-10 19:52:12 +02:00
node->nod_arg[0] = EXPR_value(0, NULL);
2001-05-23 15:26:42 +02:00
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;
2003-02-05 16:43:59 +01:00
USHORT l;
TEXT *p, *q;
2001-05-23 15:26:42 +02:00
q = DDL_token.tok_string;
l = DDL_token.tok_length;
if (DDL_token.tok_type == tok_quoted) {
q++;
l -= 2;
2003-09-30 12:39:11 +02:00
constant = (CON) DDL_alloc(sizeof(con) + l);
2001-05-23 15:26:42 +02:00
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;
2001-05-23 15:26:42 +02:00
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;
}
2002-07-06 07:32:02 +02:00
static void parse_matching_paren(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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 (!PARSE_match(KW_RIGHT_PAREN))
2001-05-23 15:26:42 +02:00
PARSE_error(243, DDL_token.tok_string, NULL); /* msg 243: expected right parenthesis, encountered \"%s\" */
}
2003-09-10 19:52:12 +02:00
static DUDLEY_NOD parse_multiply(USHORT * paren_count,
bool * bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ m u l t i p l y
*
**************************************
*
* Functional description
* Parse the operators * and /.
*
**************************************/
DUDLEY_NOD node, arg;
2001-07-12 07:46:06 +02:00
enum nod_t operatr;
2001-05-23 15:26:42 +02:00
node = parse_from(paren_count, bool_flag);
2003-09-10 19:52:12 +02:00
while (true) {
if (PARSE_match(KW_ASTERISK))
2001-07-12 07:46:06 +02:00
operatr = nod_multiply;
else if (PARSE_match(KW_SLASH))
2001-07-12 07:46:06 +02:00
operatr = nod_divide;
2001-05-23 15:26:42 +02:00
else
return node;
arg = node;
node = PARSE_make_node(operatr, 2);
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = arg;
node->nod_arg[1] = parse_from(paren_count, bool_flag);
}
}
static DUDLEY_NOD parse_not( USHORT * paren_count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ n o t
*
**************************************
*
* Functional description
* Parse a prefix NOT expression.
*
**************************************/
DUDLEY_NOD node;
2001-05-23 15:26:42 +02:00
LEX_real();
if (!PARSE_match(KW_NOT))
2001-05-23 15:26:42 +02:00
return parse_relational(paren_count);
node = PARSE_make_node(nod_not, 1);
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = parse_not(paren_count);
return node;
}
2003-09-10 19:52:12 +02:00
static DUDLEY_NOD parse_primitive_value(USHORT * paren_count,
bool * bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
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();
2003-09-10 19:52:12 +02:00
sub = parse_primitive_value(paren_count, NULL);
2001-05-23 15:26:42 +02:00
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 = PARSE_make_node(nod_negate, 1);
2001-05-23 15:26:42 +02:00
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 = PARSE_make_node(nod_null, 0);
2001-05-23 15:26:42 +02:00
break;
case KW_USER_NAME:
LEX_token();
node = PARSE_make_node(nod_user_name, 0);
2001-05-23 15:26:42 +02:00
break;
case KW_GEN_ID:
node = parse_gen_id();
break;
case KW_UPPERCASE:
LEX_token();
2003-09-10 19:52:12 +02:00
sub = parse_primitive_value(0, NULL);
node = PARSE_make_node(nod_uppercase, 1);
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = sub;
break;
default:
if (DDL_token.tok_type == tok_ident) {
if (!(node = parse_function()))
node = parse_field();
break;
}
node = PARSE_make_node(nod_literal, 1);
node->nod_arg[0] = (DUDLEY_NOD) parse_literal();
2001-05-23 15:26:42 +02:00
}
return node;
}
static DUDLEY_CTX parse_relation(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
2003-09-30 12:39:11 +02:00
context = (DUDLEY_CTX) DDL_alloc(sizeof(dudley_ctx));
2001-05-23 15:26:42 +02:00
context->ctx_name = symbol = PARSE_symbol(tok_ident);
symbol->sym_type = SYM_context;
symbol->sym_object = context;
if (!PARSE_match(KW_IN))
2001-05-23 15:26:42 +02:00
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)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2003-09-10 19:52:12 +02:00
bool negation;
2001-07-12 07:46:06 +02:00
enum nod_t operatr, *rel_ops;
2003-09-10 19:52:12 +02:00
bool local_flag = true;
2001-05-23 15:26:42 +02:00
if (PARSE_match(KW_ANY)) {
node = PARSE_make_node(nod_any, 1);
2003-09-10 19:52:12 +02:00
node->nod_arg[0] = EXPR_rse(false);
2001-05-23 15:26:42 +02:00
return node;
}
if (PARSE_match(KW_UNIQUE)) {
node = PARSE_make_node(nod_unique, 1);
2003-09-10 19:52:12 +02:00
node->nod_arg[0] = EXPR_rse(false);
2001-05-23 15:26:42 +02:00
return node;
}
expr1 = EXPR_value(paren_count, &local_flag);
if (DDL_token.tok_keyword == KW_RIGHT_PAREN)
2001-05-23 15:26:42 +02:00
return expr1;
2003-09-10 19:52:12 +02:00
negation = false;
2001-05-23 15:26:42 +02:00
node = NULL;
LEX_real();
if (PARSE_match(KW_NOT)) {
2003-09-10 19:52:12 +02:00
negation = true;
2001-05-23 15:26:42 +02:00
LEX_real();
}
switch (PARSE_keyword()) {
case KW_EQUALS:
case KW_EQ:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_neq : nod_eql;
2003-09-10 19:52:12 +02:00
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_NE:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_eql : nod_neq;
2003-09-10 19:52:12 +02:00
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_GT:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_leq : nod_gtr;
2003-09-10 19:52:12 +02:00
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_GE:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_lss : nod_geq;
2003-09-10 19:52:12 +02:00
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_LE:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_gtr : nod_leq;
2003-09-10 19:52:12 +02:00
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_LT:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_geq : nod_lss;
2003-09-10 19:52:12 +02:00
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_CONTAINING:
2001-07-12 07:46:06 +02:00
operatr = nod_containing;
2001-05-23 15:26:42 +02:00
break;
case KW_MATCHES:
LEX_token();
2003-09-10 19:52:12 +02:00
expr2 = EXPR_value(0, NULL);
if (PARSE_match(KW_USING)) {
2001-07-12 07:46:06 +02:00
operatr = nod_sleuth;
node = PARSE_make_node(operatr, 3);
2003-09-10 19:52:12 +02:00
node->nod_arg[2] = EXPR_value(0, NULL);
2001-05-23 15:26:42 +02:00
}
else {
2001-07-12 07:46:06 +02:00
operatr = nod_matches;
node = PARSE_make_node(operatr, 2);
2001-05-23 15:26:42 +02:00
}
node->nod_arg[0] = expr1;
node->nod_arg[1] = expr2;
break;
case KW_STARTS:
LEX_token();
PARSE_match(KW_WITH);
node = PARSE_make_node(nod_starts, 2);
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = expr1;
2003-09-10 19:52:12 +02:00
node->nod_arg[1] = EXPR_value(0, NULL);
2001-05-23 15:26:42 +02:00
break;
case KW_MISSING:
LEX_token();
node = PARSE_make_node(nod_missing, 1);
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = expr1;
break;
case KW_BETWEEN:
LEX_token();
node = PARSE_make_node(nod_between, 3);
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = expr1;
2003-09-10 19:52:12 +02:00
node->nod_arg[1] = EXPR_value(0, NULL);
PARSE_match(KW_AND);
2003-09-10 19:52:12 +02:00
node->nod_arg[2] = EXPR_value(0, NULL);
2001-05-23 15:26:42 +02:00
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 = PARSE_make_node(operatr, 2);
2001-05-23 15:26:42 +02:00
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 = PARSE_make_node(nod_not, 1);
2001-05-23 15:26:42 +02:00
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. */
2001-07-12 07:46:06 +02:00
if (operatr != nod_eql)
2001-05-23 15:26:42 +02:00
return node;
/* We have an equality operation, which can take a number of values. Generate
implicit ORs */
while (PARSE_match(KW_COMMA)) {
PARSE_match(KW_OR);
or_node = PARSE_make_node(nod_or, 2);
2001-05-23 15:26:42 +02:00
or_node->nod_arg[0] = node;
or_node->nod_arg[1] = node = PARSE_make_node(nod_eql, 2);
2001-05-23 15:26:42 +02:00
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)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s o r t
*
**************************************
*
* Functional description
* Parse a sort list.
*
**************************************/
LLS stack;
SSHORT direction;
direction = 0;
stack = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
LEX_real();
if (PARSE_match(KW_ASCENDING))
2001-05-23 15:26:42 +02:00
direction = 0;
else if (PARSE_match(KW_DESCENDING))
2001-05-23 15:26:42 +02:00
direction = 1;
2003-09-10 19:52:12 +02:00
LLS_PUSH(EXPR_value(0, NULL), &stack);
LLS_PUSH((DUDLEY_NOD) (SLONG) direction, &stack);
if (!PARSE_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
return PARSE_make_list(stack);
}
static DUDLEY_NOD parse_statistical(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s t a t i s t i c a l
*
**************************************
*
* Functional description
* Parse statistical expression.
*
**************************************/
2003-09-30 12:39:11 +02:00
nod_types* types;
DUDLEY_NOD node;
2001-05-23 15:26:42 +02:00
enum kwwords keyword;
keyword = PARSE_keyword();
LEX_token();
for (types = statisticals;; types++)
if (types->nod_t_keyword == keyword)
break;
node = PARSE_make_node(types->nod_t_node, s_stt_count);
2001-05-23 15:26:42 +02:00
if (node->nod_type != nod_count)
2003-09-10 19:52:12 +02:00
node->nod_arg[s_stt_value] = EXPR_value(0, NULL);
2001-05-23 15:26:42 +02:00
if (!PARSE_match(KW_OF))
2001-05-23 15:26:42 +02:00
PARSE_error(246, DDL_token.tok_string, NULL); /* msg 246: expected OF, encountered \"%s\" */
2003-09-10 19:52:12 +02:00
node->nod_arg[s_stt_rse] = EXPR_rse(false);
2001-05-23 15:26:42 +02:00
return node;
}
2002-07-06 07:32:02 +02:00
static void parse_terminating_parens(USHORT * paren_count,
USHORT * local_count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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));
}