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

1164 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/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(const TEXT*, USHORT);
2003-09-10 19:52:12 +02:00
static DUDLEY_NOD parse_add(USHORT *, bool *);
static DUDLEY_NOD parse_and(USHORT *);
2009-01-14 12:10:48 +01:00
static DUDLEY_NOD parse_field();
2003-09-10 19:52:12 +02:00
static DUDLEY_NOD parse_from(USHORT *, bool *);
2009-01-14 12:10:48 +01:00
static DUDLEY_NOD parse_function();
static DUDLEY_NOD parse_gen_id();
static CON parse_literal();
static void parse_matching_paren();
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 *);
2009-01-14 12:10:48 +01:00
static DUDLEY_CTX parse_relation();
static DUDLEY_NOD parse_relational(USHORT *);
2009-01-14 12:10:48 +01:00
static DUDLEY_NOD parse_sort();
static DUDLEY_NOD parse_statistical();
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;
2004-02-02 12:02:12 +01:00
dudley_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) {
2007-04-02 13:25:45 +02:00
PARSE_error(234, 0); /* msg 234: OVER can only be used in CROSS expressions */
2001-05-23 15:26:42 +02:00
}
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)
2007-04-02 13:25:45 +02:00
PARSE_error(319, 0); /* 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;
}
2009-01-14 12:10:48 +01:00
DUDLEY_NOD EXPR_statement()
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.
*
**************************************/
2004-02-02 12:02:12 +01:00
dudley_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)
2007-04-02 13:25:45 +02:00
PARSE_error(235, 0); /* msg 235: abort code cannot exceed 255 */
2004-03-14 06:51:54 +01:00
node->nod_arg[0] = (DUDLEY_NOD) (IPTR) 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))
PARSE_error(236, dudleyGlob.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( const TEXT* string, USHORT length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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.
*
**************************************/
const TEXT* p = string;
USHORT l = length;
2001-05-23 15:26:42 +02:00
CON 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);
2004-12-08 06:58:41 +01:00
SLONG* number = (SLONG *) constant->con_data;
constant->con_desc.dsc_address = (UCHAR*) (IPTR) number;
USHORT scale = 0;
2001-05-23 15:26:42 +02:00
do {
2004-12-08 06:58:41 +01:00
const TEXT c = *p++;
if (c == '.')
2001-05-23 15:26:42 +02:00
scale = 1;
else {
/* The right side of the following comparison had originally been:
2004-12-08 06:58:41 +01:00
((1 << 31) - 1) / 10
2001-05-23 15:26:42 +02:00
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;
2001-05-23 15:26:42 +02:00
constant->con_desc.dsc_length = length;
constant->con_desc.dsc_address = constant->con_data;
TEXT* q = (TEXT *) constant->con_desc.dsc_address;
2001-05-23 15:26:42 +02:00
p = string;
*q++ = ' ';
2004-12-08 06:58:41 +01:00
bool fraction = false;
2001-05-23 15:26:42 +02:00
for (l = 1; l < length; p++, l++)
if (*p >= '0' && *p <= '9')
*q++ = *p;
else if (*p == '.') {
*q++ = *p;
if (fraction)
DDL_err(237); /* msg 237: too many decimal points */
2001-05-23 15:26:42 +02:00
else
2004-12-08 06:58:41 +01:00
fraction = true;
2001-05-23 15:26:42 +02:00
}
else
DDL_err(238); /* msg 238: unrecognized character in numeric string */
2001-05-23 15:26:42 +02:00
}
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;
}
2009-01-14 12:10:48 +01:00
static DUDLEY_NOD parse_field()
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;
2004-02-02 12:02:12 +01:00
dudley_lls* stack;
2001-05-23 15:26:42 +02:00
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))
PARSE_error(317, dudleyGlob.DDL_token.tok_string, NULL); /* msg 317, expected comma or right bracket, encountered \"%s\" */
2001-05-23 15:26:42 +02:00
}
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))
PARSE_error(239, dudleyGlob.DDL_token.tok_string, NULL);
2001-05-23 15:26:42 +02:00
/* 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;
}
2009-01-14 12:10:48 +01:00
static DUDLEY_NOD parse_function()
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;
2004-02-02 12:02:12 +01:00
dudley_lls* stack;
2001-05-23 15:26:42 +02:00
/* Look for symbol of type function. If we don't find it, give up */
for (symbol = dudleyGlob.DDL_token.tok_symbol; symbol; symbol = symbol->sym_homonym)
2001-05-23 15:26:42 +02:00
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))
PARSE_error(240, dudleyGlob.DDL_token.tok_string, NULL);
2001-05-23 15:26:42 +02:00
/* msg 240: expected comma or right parenthesis, encountered \"%s\" */
}
node->nod_arg[0] = PARSE_make_list(stack);
return node;
}
2009-01-14 12:10:48 +01:00
static DUDLEY_NOD parse_gen_id()
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))
PARSE_error(241, dudleyGlob.DDL_token.tok_string, NULL); /* msg 241: expected left parenthesis, encountered \"%s\" */
2001-05-23 15:26:42 +02:00
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;
}
2009-01-14 12:10:48 +01:00
static CON parse_literal()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ l i t e r a l
*
**************************************
*
* Functional description
* Parse a literal expression.
*
**************************************/
CON constant;
const TEXT* q = dudleyGlob.DDL_token.tok_string;
USHORT l = dudleyGlob.DDL_token.tok_length;
2001-05-23 15:26:42 +02:00
if (dudleyGlob.DDL_token.tok_type == tok_quoted) {
2001-05-23 15:26:42 +02:00
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;
TEXT* 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)
2009-05-03 23:57:13 +02:00
{
do
{
2001-05-23 15:26:42 +02:00
*p++ = *q++;
} while (--l);
2009-05-03 23:57:13 +02:00
}
2001-05-23 15:26:42 +02:00
}
else if (dudleyGlob.DDL_token.tok_type == tok_number) {
constant = make_numeric_constant(dudleyGlob.DDL_token.tok_string,
dudleyGlob.DDL_token.tok_length);
2001-05-23 15:26:42 +02:00
}
else {
PARSE_error(242, dudleyGlob.DDL_token.tok_string, NULL); /* msg 242: expected value expression, encountered \"%s\" */
return NULL; // silence non initialized warning
}
2001-05-23 15:26:42 +02:00
LEX_token();
return constant;
}
2009-01-14 12:10:48 +01:00
static void parse_matching_paren()
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))
PARSE_error(243, dudleyGlob.DDL_token.tok_string, NULL); /* msg 243: expected right parenthesis, encountered \"%s\" */
2001-05-23 15:26:42 +02:00
}
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;
USHORT local_count;
if (!paren_count) {
local_count = 0;
paren_count = &local_count;
}
TEXT *p;
2001-05-23 15:26:42 +02:00
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 (dudleyGlob.DDL_token.tok_type == tok_ident) {
2001-05-23 15:26:42 +02:00
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;
}
2009-01-14 12:10:48 +01:00
static DUDLEY_CTX parse_relation()
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))
PARSE_error(244, dudleyGlob.DDL_token.tok_string, NULL); /* msg 244: expected IN, encountered \"%s\" */
2001-05-23 15:26:42 +02:00
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, expr2;
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;
}
bool local_flag = true;
DUDLEY_NOD expr1 = EXPR_value(paren_count, &local_flag);
if (dudleyGlob.DDL_token.tok_keyword == KW_RIGHT_PAREN)
2001-05-23 15:26:42 +02:00
return expr1;
bool 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();
}
enum nod_t operatr;
2009-02-28 12:57:40 +01:00
switch (PARSE_keyword())
{
2001-05-23 15:26:42 +02:00
case KW_EQUALS:
case KW_EQ:
2009-02-28 12:57:40 +01: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:
2009-02-28 12:57:40 +01: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:
2009-02-28 12:57:40 +01: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:
2009-02-28 12:57:40 +01: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:
2009-02-28 12:57:40 +01: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:
2009-02-28 12:57:40 +01: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(nod_sleuth, 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(nod_matches, 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);
operatr = nod_starts;
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();
operatr = nod_missing;
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();
operatr = nod_between;
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 (enum nod_t* rel_ops = relationals; *rel_ops != (enum nod_t) 0; rel_ops++)
2001-05-23 15:26:42 +02:00
if (expr1->nod_type == *rel_ops)
return expr1;
PARSE_error(245, dudleyGlob.DDL_token.tok_string, NULL);
/* msg 245: expected relational operator, encountered \"%s\" */
return NULL; // silence non initialized warning
2001-05-23 15:26:42 +02:00
}
/* 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);
DUDLEY_NOD 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;
}
2009-01-14 12:10:48 +01:00
static DUDLEY_NOD parse_sort()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s o r t
*
**************************************
*
* Functional description
* Parse a sort list.
*
**************************************/
2004-02-02 12:02:12 +01:00
dudley_lls* stack;
2001-05-23 15:26:42 +02:00
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);
2004-03-14 06:51:54 +01:00
LLS_PUSH((DUDLEY_NOD) (IPTR) direction, &stack);
if (!PARSE_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
return PARSE_make_list(stack);
}
2009-01-14 12:10:48 +01:00
static DUDLEY_NOD parse_statistical()
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))
PARSE_error(246, dudleyGlob.DDL_token.tok_string, NULL); /* msg 246: expected OF, encountered \"%s\" */
2001-05-23 15:26:42 +02:00
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)
2009-05-03 23:57:13 +02:00
{
do
{
2001-05-23 15:26:42 +02:00
parse_matching_paren();
} while (--(*paren_count));
2009-05-03 23:57:13 +02:00
}
2001-05-23 15:26:42 +02:00
}