2014-10-09 01:30:22 +02:00
|
|
|
%{
|
2014-10-22 15:43:27 +02:00
|
|
|
/**
|
|
|
|
* bison_parser.y
|
|
|
|
* defines bison_parser.h
|
|
|
|
* outputs bison_parser.c
|
|
|
|
*
|
|
|
|
* Grammar File Spec: http://dinosaur.compilertools.net/bison/bison_6.html
|
|
|
|
*
|
2014-10-09 01:30:22 +02:00
|
|
|
*/
|
2014-10-22 15:43:27 +02:00
|
|
|
/*********************************
|
|
|
|
** Section 1: C Declarations
|
|
|
|
*********************************/
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2015-12-23 16:01:08 +01:00
|
|
|
#include "../sqltypes.h"
|
2014-10-16 15:35:38 +02:00
|
|
|
#include "bison_parser.h"
|
|
|
|
#include "flex_lexer.h"
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-10-22 15:43:27 +02:00
|
|
|
#include <stdio.h>
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-10-31 18:36:02 +01:00
|
|
|
using namespace hsql;
|
|
|
|
|
2014-12-15 14:43:42 +01:00
|
|
|
int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const char *msg) {
|
2014-11-07 02:00:09 +01:00
|
|
|
|
2014-12-03 17:43:02 +01:00
|
|
|
SQLStatementList* list = new SQLStatementList();
|
2014-11-07 02:00:09 +01:00
|
|
|
list->isValid = false;
|
|
|
|
list->parser_msg = strdup(msg);
|
2014-12-15 14:43:42 +01:00
|
|
|
list->error_line = llocp->first_line;
|
|
|
|
list->error_col = llocp->first_column;
|
2014-12-15 15:01:01 +01:00
|
|
|
|
2014-11-07 02:00:09 +01:00
|
|
|
*result = list;
|
2014-10-22 15:43:27 +02:00
|
|
|
return 0;
|
2014-10-09 01:30:22 +02:00
|
|
|
}
|
|
|
|
|
2014-12-15 16:43:32 +01:00
|
|
|
|
|
|
|
|
2014-10-09 01:30:22 +02:00
|
|
|
%}
|
2014-10-22 15:43:27 +02:00
|
|
|
/*********************************
|
|
|
|
** Section 2: Bison Parser Declarations
|
|
|
|
*********************************/
|
|
|
|
|
|
|
|
|
|
|
|
// Specify code that is included in the generated .h and .c files
|
2014-10-09 01:30:22 +02:00
|
|
|
%code requires {
|
2014-12-15 16:43:32 +01:00
|
|
|
// %code requires block
|
|
|
|
#include "parser_typedef.h"
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-12-15 16:43:32 +01:00
|
|
|
// Auto update column and line number
|
2014-12-15 14:43:42 +01:00
|
|
|
#define YY_USER_ACTION \
|
|
|
|
yylloc->first_line = yylloc->last_line; \
|
|
|
|
yylloc->first_column = yylloc->last_column; \
|
|
|
|
for(int i = 0; yytext[i] != '\0'; i++) { \
|
2015-01-06 15:29:18 +01:00
|
|
|
yylloc->total_column++; \
|
2014-12-15 14:43:42 +01:00
|
|
|
if(yytext[i] == '\n') { \
|
|
|
|
yylloc->last_line++; \
|
|
|
|
yylloc->last_column = 0; \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
yylloc->last_column++; \
|
|
|
|
} \
|
|
|
|
}
|
2014-10-09 01:30:22 +02:00
|
|
|
}
|
|
|
|
|
2014-12-15 16:43:32 +01:00
|
|
|
// Define the names of the created files
|
|
|
|
%output "bison_parser.cpp"
|
|
|
|
%defines "bison_parser.h"
|
|
|
|
|
|
|
|
// Tell bison to create a reentrant parser
|
|
|
|
%define api.pure full
|
|
|
|
|
|
|
|
// Prefix the parser
|
|
|
|
%define api.prefix {hsql_}
|
|
|
|
%define api.token.prefix {SQL_}
|
|
|
|
|
|
|
|
%define parse.error verbose
|
|
|
|
%locations
|
|
|
|
|
|
|
|
%initial-action {
|
|
|
|
// Initialize
|
|
|
|
@$.first_column = 0;
|
|
|
|
@$.last_column = 0;
|
|
|
|
@$.first_line = 0;
|
|
|
|
@$.last_line = 0;
|
2015-01-06 15:29:18 +01:00
|
|
|
@$.total_column = 0;
|
2014-12-15 16:43:32 +01:00
|
|
|
@$.placeholder_id = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-10-22 15:43:27 +02:00
|
|
|
// Define additional parameters for yylex (http://www.gnu.org/software/bison/manual/html_node/Pure-Calling.html)
|
2014-10-09 01:30:22 +02:00
|
|
|
%lex-param { yyscan_t scanner }
|
2014-10-22 15:43:27 +02:00
|
|
|
|
|
|
|
// Define additional parameters for yyparse
|
2014-12-03 17:43:02 +01:00
|
|
|
%parse-param { hsql::SQLStatementList** result }
|
2014-10-09 01:30:22 +02:00
|
|
|
%parse-param { yyscan_t scanner }
|
|
|
|
|
2014-10-22 15:43:27 +02:00
|
|
|
|
|
|
|
/*********************************
|
|
|
|
** Define all data-types (http://www.gnu.org/software/bison/manual/html_node/Union-Decl.html)
|
|
|
|
*********************************/
|
2014-10-09 01:30:22 +02:00
|
|
|
%union {
|
2014-10-27 13:54:16 +01:00
|
|
|
double fval;
|
|
|
|
int64_t ival;
|
2014-10-09 01:30:22 +02:00
|
|
|
char* sval;
|
2014-10-27 14:54:15 +01:00
|
|
|
uint uval;
|
2014-11-17 02:18:31 +01:00
|
|
|
bool bval;
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-12-03 17:43:02 +01:00
|
|
|
hsql::SQLStatement* statement;
|
2014-12-15 16:43:32 +01:00
|
|
|
hsql::SelectStatement* select_stmt;
|
|
|
|
hsql::ImportStatement* import_stmt;
|
|
|
|
hsql::CreateStatement* create_stmt;
|
|
|
|
hsql::InsertStatement* insert_stmt;
|
|
|
|
hsql::DeleteStatement* delete_stmt;
|
|
|
|
hsql::UpdateStatement* update_stmt;
|
|
|
|
hsql::DropStatement* drop_stmt;
|
|
|
|
hsql::PrepareStatement* prep_stmt;
|
|
|
|
hsql::ExecuteStatement* exec_stmt;
|
2014-11-03 23:26:33 +01:00
|
|
|
|
2014-10-31 18:36:02 +01:00
|
|
|
hsql::TableRef* table;
|
|
|
|
hsql::Expr* expr;
|
|
|
|
hsql::OrderDescription* order;
|
|
|
|
hsql::OrderType order_type;
|
|
|
|
hsql::LimitDescription* limit;
|
2014-11-26 18:20:10 +01:00
|
|
|
hsql::ColumnDefinition* column_t;
|
2014-12-18 12:11:26 +01:00
|
|
|
hsql::GroupByDescription* group_t;
|
2014-12-02 01:27:02 +01:00
|
|
|
hsql::UpdateClause* update_t;
|
2014-10-31 18:36:02 +01:00
|
|
|
|
2014-12-03 17:43:02 +01:00
|
|
|
hsql::SQLStatementList* stmt_list;
|
2015-01-06 19:47:59 +01:00
|
|
|
|
|
|
|
std::vector<char*>* str_vec;
|
|
|
|
std::vector<hsql::TableRef*>* table_vec;
|
|
|
|
std::vector<hsql::ColumnDefinition*>* column_vec;
|
|
|
|
std::vector<hsql::UpdateClause*>* update_vec;
|
|
|
|
std::vector<hsql::Expr*>* expr_vec;
|
2014-10-09 01:30:22 +02:00
|
|
|
}
|
|
|
|
|
2014-10-09 04:46:25 +02:00
|
|
|
|
2014-10-22 15:43:27 +02:00
|
|
|
|
|
|
|
/*********************************
|
|
|
|
** Token Definition
|
|
|
|
*********************************/
|
2014-11-12 10:43:10 +01:00
|
|
|
%token <sval> IDENTIFIER STRING
|
2014-12-03 16:32:56 +01:00
|
|
|
%token <fval> FLOATVAL
|
|
|
|
%token <ival> INTVAL
|
2014-11-07 16:29:46 +01:00
|
|
|
%token <uval> NOTEQUALS LESSEQ GREATEREQ
|
|
|
|
|
|
|
|
/* SQL Keywords */
|
2014-12-15 14:43:42 +01:00
|
|
|
%token DEALLOCATE PARAMETERS INTERSECT TEMPORARY TIMESTAMP
|
|
|
|
%token DISTINCT NVARCHAR RESTRICT TRUNCATE ANALYZE BETWEEN
|
|
|
|
%token CASCADE COLUMNS CONTROL DEFAULT EXECUTE EXPLAIN
|
|
|
|
%token HISTORY INTEGER NATURAL PREPARE PRIMARY SCHEMAS
|
|
|
|
%token SPATIAL VIRTUAL BEFORE COLUMN CREATE DELETE DIRECT
|
|
|
|
%token DOUBLE ESCAPE EXCEPT EXISTS GLOBAL HAVING IMPORT
|
|
|
|
%token INSERT ISNULL OFFSET RENAME SCHEMA SELECT SORTED
|
|
|
|
%token TABLES UNIQUE UNLOAD UPDATE VALUES AFTER ALTER CROSS
|
|
|
|
%token DELTA GROUP INDEX INNER LIMIT LOCAL MERGE MINUS ORDER
|
|
|
|
%token OUTER RIGHT TABLE UNION USING WHERE CALL DATE DESC
|
|
|
|
%token DROP FILE FROM FULL HASH HINT INTO JOIN LEFT LIKE
|
|
|
|
%token LOAD NULL PART PLAN SHOW TEXT TIME VIEW WITH ADD ALL
|
|
|
|
%token AND ASC CSV FOR INT KEY NOT OFF SET TBL TOP AS BY IF
|
|
|
|
%token IN IS OF ON OR TO
|
2014-11-07 16:29:46 +01:00
|
|
|
|
2014-10-22 15:43:27 +02:00
|
|
|
|
|
|
|
/*********************************
|
|
|
|
** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html)
|
|
|
|
*********************************/
|
2014-11-07 02:00:09 +01:00
|
|
|
%type <stmt_list> statement_list
|
2014-12-15 15:01:01 +01:00
|
|
|
%type <statement> statement preparable_statement
|
2014-12-15 16:43:32 +01:00
|
|
|
%type <exec_stmt> execute_statement
|
|
|
|
%type <prep_stmt> prepare_statement
|
2014-11-26 00:26:20 +01:00
|
|
|
%type <select_stmt> select_statement select_with_paren select_no_paren select_clause
|
2014-11-07 01:09:06 +01:00
|
|
|
%type <import_stmt> import_statement
|
2014-11-12 00:11:07 +01:00
|
|
|
%type <create_stmt> create_statement
|
2014-11-26 00:26:20 +01:00
|
|
|
%type <insert_stmt> insert_statement
|
2014-11-26 14:43:22 +01:00
|
|
|
%type <delete_stmt> delete_statement truncate_statement
|
2014-12-02 01:27:02 +01:00
|
|
|
%type <update_stmt> update_statement
|
2014-12-03 16:53:49 +01:00
|
|
|
%type <drop_stmt> drop_statement
|
2014-11-07 01:09:06 +01:00
|
|
|
%type <sval> table_name opt_alias alias file_path
|
2014-12-18 12:28:24 +01:00
|
|
|
%type <bval> opt_not_exists opt_distinct
|
2014-11-26 18:20:10 +01:00
|
|
|
%type <uval> import_file_type opt_join_type column_type
|
2014-11-04 01:42:09 +01:00
|
|
|
%type <table> from_clause table_ref table_ref_atomic table_ref_name
|
2014-12-02 01:27:02 +01:00
|
|
|
%type <table> join_clause join_table table_ref_name_no_alias
|
2014-12-15 15:01:01 +01:00
|
|
|
%type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr expr_alias placeholder_expr
|
2014-11-07 02:00:09 +01:00
|
|
|
%type <expr> column_name literal int_literal num_literal string_literal
|
2014-12-18 12:11:26 +01:00
|
|
|
%type <expr> comp_expr opt_where join_condition opt_having
|
2014-11-13 01:27:47 +01:00
|
|
|
%type <order> opt_order
|
|
|
|
%type <limit> opt_limit
|
|
|
|
%type <order_type> opt_order_type
|
2015-01-06 19:47:59 +01:00
|
|
|
%type <column_t> column_def
|
|
|
|
%type <update_t> update_clause
|
|
|
|
%type <group_t> opt_group
|
|
|
|
|
|
|
|
%type <str_vec> ident_commalist opt_column_list
|
|
|
|
%type <expr_vec> expr_list select_list literal_list
|
|
|
|
%type <table_vec> table_ref_commalist
|
|
|
|
%type <update_vec> update_clause_commalist
|
|
|
|
%type <column_vec> column_def_commalist
|
2014-10-22 15:43:27 +02:00
|
|
|
|
2014-10-24 16:10:38 +02:00
|
|
|
/******************************
|
|
|
|
** Token Precedence and Associativity
|
|
|
|
** Precedence: lowest to highest
|
|
|
|
******************************/
|
|
|
|
%left OR
|
|
|
|
%left AND
|
|
|
|
%right NOT
|
2014-11-05 15:54:41 +01:00
|
|
|
%right '=' EQUALS NOTEQUALS LIKE
|
2014-10-24 16:10:38 +02:00
|
|
|
%nonassoc '<' '>' LESS GREATER LESSEQ GREATEREQ
|
|
|
|
|
|
|
|
%nonassoc NOTNULL
|
|
|
|
%nonassoc ISNULL
|
|
|
|
%nonassoc IS /* sets precedence for IS NULL, etc */
|
|
|
|
%left '+' '-'
|
|
|
|
%left '*' '/' '%'
|
|
|
|
%left '^'
|
|
|
|
|
|
|
|
/* Unary Operators */
|
2014-11-04 01:42:09 +01:00
|
|
|
%right UMINUS
|
2014-10-24 16:10:38 +02:00
|
|
|
%left '[' ']'
|
|
|
|
%left '(' ')'
|
|
|
|
%left '.'
|
2014-10-22 15:43:27 +02:00
|
|
|
|
2014-10-09 01:30:22 +02:00
|
|
|
%%
|
2014-10-22 15:43:27 +02:00
|
|
|
/*********************************
|
|
|
|
** Section 3: Grammar Definition
|
|
|
|
*********************************/
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-10-22 15:43:27 +02:00
|
|
|
// Defines our general input.
|
2014-10-20 22:33:36 +02:00
|
|
|
input:
|
2015-01-07 13:24:39 +01:00
|
|
|
statement_list opt_semicolon {
|
2015-01-06 15:29:18 +01:00
|
|
|
*result = $1;
|
|
|
|
}
|
2014-11-07 02:00:09 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
statement_list:
|
2014-12-03 17:43:02 +01:00
|
|
|
statement { $$ = new SQLStatementList($1); }
|
2015-01-06 19:47:59 +01:00
|
|
|
| statement_list ';' statement { $1->addStatement($3); $$ = $1; }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-10-09 02:55:07 +02:00
|
|
|
statement:
|
2015-01-07 13:24:39 +01:00
|
|
|
prepare_statement {
|
|
|
|
$1->setPlaceholders(yyloc.placeholder_list);
|
|
|
|
yyloc.placeholder_list.clear();
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
|
|
| preparable_statement
|
2014-12-15 14:43:42 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
preparable_statement:
|
2014-10-09 02:55:07 +02:00
|
|
|
select_statement { $$ = $1; }
|
2014-11-07 01:09:06 +01:00
|
|
|
| import_statement { $$ = $1; }
|
2014-11-12 00:11:07 +01:00
|
|
|
| create_statement { $$ = $1; }
|
2014-11-26 00:26:20 +01:00
|
|
|
| insert_statement { $$ = $1; }
|
2014-11-26 14:43:22 +01:00
|
|
|
| delete_statement { $$ = $1; }
|
|
|
|
| truncate_statement { $$ = $1; }
|
2014-12-02 01:27:02 +01:00
|
|
|
| update_statement { $$ = $1; }
|
2014-12-03 16:53:49 +01:00
|
|
|
| drop_statement { $$ = $1; }
|
2014-12-15 15:01:01 +01:00
|
|
|
| execute_statement { $$ = $1; }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
2014-10-09 01:30:22 +02:00
|
|
|
|
|
|
|
|
2014-12-15 14:43:42 +01:00
|
|
|
/******************************
|
|
|
|
* Prepared Statement
|
|
|
|
******************************/
|
|
|
|
prepare_statement:
|
2015-01-07 13:24:39 +01:00
|
|
|
PREPARE IDENTIFIER ':' preparable_statement {
|
|
|
|
$$ = new PrepareStatement();
|
|
|
|
$$->name = $2;
|
|
|
|
$$->query = new SQLStatementList($4);
|
|
|
|
}
|
|
|
|
| PREPARE IDENTIFIER '{' statement_list opt_semicolon '}' {
|
2014-12-15 16:43:32 +01:00
|
|
|
$$ = new PrepareStatement();
|
|
|
|
$$->name = $2;
|
2015-01-06 15:29:18 +01:00
|
|
|
$$->query = $4;
|
2014-12-15 16:43:32 +01:00
|
|
|
}
|
2014-12-15 14:43:42 +01:00
|
|
|
;
|
|
|
|
|
2014-12-15 15:01:01 +01:00
|
|
|
execute_statement:
|
2015-01-06 19:20:52 +01:00
|
|
|
EXECUTE IDENTIFIER {
|
|
|
|
$$ = new ExecuteStatement();
|
|
|
|
$$->name = $2;
|
|
|
|
}
|
|
|
|
| EXECUTE IDENTIFIER '(' literal_list ')' {
|
2014-12-15 16:43:32 +01:00
|
|
|
$$ = new ExecuteStatement();
|
|
|
|
$$->name = $2;
|
|
|
|
$$->parameters = $4;
|
|
|
|
}
|
2014-12-15 15:01:01 +01:00
|
|
|
;
|
2014-12-15 14:43:42 +01:00
|
|
|
|
2014-11-03 23:26:33 +01:00
|
|
|
|
2014-11-07 01:09:06 +01:00
|
|
|
/******************************
|
2014-11-26 14:43:22 +01:00
|
|
|
* Import Statement
|
2014-11-07 01:09:06 +01:00
|
|
|
******************************/
|
|
|
|
import_statement:
|
|
|
|
IMPORT FROM import_file_type FILE file_path INTO table_name {
|
2014-12-03 17:43:02 +01:00
|
|
|
$$ = new ImportStatement((ImportStatement::ImportType) $3);
|
2014-11-07 01:09:06 +01:00
|
|
|
$$->file_path = $5;
|
|
|
|
$$->table_name = $7;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
import_file_type:
|
2014-12-03 17:43:02 +01:00
|
|
|
CSV { $$ = ImportStatement::kImportCSV; }
|
2014-11-07 01:09:06 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
file_path:
|
2014-11-07 02:00:09 +01:00
|
|
|
string_literal { $$ = $1->name; }
|
2014-11-07 01:09:06 +01:00
|
|
|
;
|
2014-11-03 23:26:33 +01:00
|
|
|
|
|
|
|
|
2014-11-12 00:11:07 +01:00
|
|
|
/******************************
|
2014-11-26 14:43:22 +01:00
|
|
|
* Create Statement
|
|
|
|
* CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)
|
|
|
|
* CREATE TABLE students FROM TBL FILE 'test/students.tbl'
|
2014-11-12 00:11:07 +01:00
|
|
|
******************************/
|
|
|
|
create_statement:
|
2014-11-17 02:18:31 +01:00
|
|
|
CREATE TABLE opt_not_exists table_name FROM TBL FILE file_path {
|
2014-12-03 17:43:02 +01:00
|
|
|
$$ = new CreateStatement(CreateStatement::kTableFromTbl);
|
2014-11-17 02:18:31 +01:00
|
|
|
$$->if_not_exists = $3;
|
|
|
|
$$->table_name = $4;
|
|
|
|
$$->file_path = $8;
|
2014-11-12 00:11:07 +01:00
|
|
|
}
|
2014-11-26 14:43:22 +01:00
|
|
|
| CREATE TABLE opt_not_exists table_name '(' column_def_commalist ')' {
|
2014-12-03 17:43:02 +01:00
|
|
|
$$ = new CreateStatement(CreateStatement::kTable);
|
2014-11-26 14:43:22 +01:00
|
|
|
$$->if_not_exists = $3;
|
|
|
|
$$->table_name = $4;
|
2014-11-26 18:20:10 +01:00
|
|
|
$$->columns = $6;
|
2014-11-26 14:43:22 +01:00
|
|
|
}
|
2014-11-12 00:11:07 +01:00
|
|
|
;
|
|
|
|
|
2014-11-17 02:18:31 +01:00
|
|
|
opt_not_exists:
|
|
|
|
IF NOT EXISTS { $$ = true; }
|
|
|
|
| /* empty */ { $$ = false; }
|
|
|
|
;
|
2014-11-12 00:11:07 +01:00
|
|
|
|
2014-11-26 14:43:22 +01:00
|
|
|
column_def_commalist:
|
2015-01-06 19:47:59 +01:00
|
|
|
column_def { $$ = new std::vector<ColumnDefinition*>(); $$->push_back($1); }
|
2014-11-26 18:20:10 +01:00
|
|
|
| column_def_commalist ',' column_def { $1->push_back($3); $$ = $1; }
|
2014-11-26 14:43:22 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
column_def:
|
2014-11-26 18:20:10 +01:00
|
|
|
IDENTIFIER column_type {
|
|
|
|
$$ = new ColumnDefinition($1, (ColumnDefinition::DataType) $2);
|
|
|
|
}
|
2014-11-26 14:43:22 +01:00
|
|
|
;
|
|
|
|
|
2014-12-03 16:32:56 +01:00
|
|
|
|
2014-11-26 14:43:22 +01:00
|
|
|
column_type:
|
2014-12-03 16:32:56 +01:00
|
|
|
INT { $$ = ColumnDefinition::INT; }
|
|
|
|
| INTEGER { $$ = ColumnDefinition::INT; }
|
2014-11-26 18:20:10 +01:00
|
|
|
| DOUBLE { $$ = ColumnDefinition::DOUBLE; }
|
|
|
|
| TEXT { $$ = ColumnDefinition::TEXT; }
|
2014-11-26 14:43:22 +01:00
|
|
|
;
|
|
|
|
|
2014-12-03 16:53:49 +01:00
|
|
|
/******************************
|
|
|
|
* Drop Statement
|
2015-01-07 13:42:11 +01:00
|
|
|
* DROP TABLE students;
|
|
|
|
* DEALLOCATE PREPARE stmt;
|
2014-12-03 16:53:49 +01:00
|
|
|
******************************/
|
|
|
|
|
|
|
|
drop_statement:
|
|
|
|
DROP TABLE table_name {
|
|
|
|
$$ = new DropStatement(DropStatement::kTable);
|
|
|
|
$$->name = $3;
|
|
|
|
}
|
2015-01-07 13:42:11 +01:00
|
|
|
| DEALLOCATE PREPARE IDENTIFIER {
|
|
|
|
$$ = new DropStatement(DropStatement::kPreparedStatement);
|
|
|
|
$$->name = $3;
|
|
|
|
}
|
|
|
|
;
|
2014-11-26 14:43:22 +01:00
|
|
|
|
|
|
|
/******************************
|
|
|
|
* Delete Statement / Truncate statement
|
|
|
|
* DELETE FROM students WHERE grade > 3.0
|
|
|
|
* DELETE FROM students <=> TRUNCATE students
|
|
|
|
******************************/
|
|
|
|
delete_statement:
|
|
|
|
DELETE FROM table_name opt_where {
|
|
|
|
$$ = new DeleteStatement();
|
|
|
|
$$->table_name = $3;
|
|
|
|
$$->expr = $4;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
truncate_statement:
|
|
|
|
TRUNCATE table_name {
|
|
|
|
$$ = new DeleteStatement();
|
|
|
|
$$->table_name = $2;
|
|
|
|
}
|
|
|
|
;
|
2014-11-26 00:26:20 +01:00
|
|
|
|
|
|
|
/******************************
|
2014-11-26 14:43:22 +01:00
|
|
|
* Insert Statement
|
|
|
|
* INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)
|
|
|
|
* INSERT INTO employees SELECT * FROM stundents
|
2014-11-26 00:26:20 +01:00
|
|
|
******************************/
|
|
|
|
insert_statement:
|
|
|
|
INSERT INTO table_name opt_column_list VALUES '(' literal_list ')' {
|
2014-12-03 17:43:02 +01:00
|
|
|
$$ = new InsertStatement(InsertStatement::kInsertValues);
|
2014-11-26 00:26:20 +01:00
|
|
|
$$->table_name = $3;
|
|
|
|
$$->columns = $4;
|
|
|
|
$$->values = $7;
|
|
|
|
}
|
|
|
|
| INSERT INTO table_name opt_column_list select_no_paren {
|
2014-12-03 17:43:02 +01:00
|
|
|
$$ = new InsertStatement(InsertStatement::kInsertSelect);
|
2014-11-26 00:26:20 +01:00
|
|
|
$$->table_name = $3;
|
|
|
|
$$->columns = $4;
|
|
|
|
$$->select = $5;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
opt_column_list:
|
|
|
|
'(' ident_commalist ')' { $$ = $2; }
|
|
|
|
| /* empty */ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
2014-12-02 01:27:02 +01:00
|
|
|
|
|
|
|
/******************************
|
|
|
|
* Update Statement
|
|
|
|
* UPDATE students SET grade = 1.3, name='Felix Fürstenberg' WHERE name = 'Max Mustermann';
|
|
|
|
******************************/
|
|
|
|
|
|
|
|
update_statement:
|
|
|
|
UPDATE table_ref_name_no_alias SET update_clause_commalist opt_where {
|
|
|
|
$$ = new UpdateStatement();
|
|
|
|
$$->table = $2;
|
|
|
|
$$->updates = $4;
|
|
|
|
$$->where = $5;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
update_clause_commalist:
|
2015-01-06 19:47:59 +01:00
|
|
|
update_clause { $$ = new std::vector<UpdateClause*>(); $$->push_back($1); }
|
2014-12-02 01:27:02 +01:00
|
|
|
| update_clause_commalist ',' update_clause { $1->push_back($3); $$ = $1; }
|
|
|
|
;
|
|
|
|
|
|
|
|
update_clause:
|
|
|
|
IDENTIFIER '=' literal {
|
|
|
|
$$ = new UpdateClause();
|
|
|
|
$$->column = $1;
|
|
|
|
$$->value = $3;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2014-10-22 15:43:27 +02:00
|
|
|
/******************************
|
2014-11-26 14:43:22 +01:00
|
|
|
* Select Statement
|
2014-10-22 15:43:27 +02:00
|
|
|
******************************/
|
2014-10-09 01:30:22 +02:00
|
|
|
|
|
|
|
select_statement:
|
2014-11-13 01:27:47 +01:00
|
|
|
select_with_paren
|
|
|
|
| select_no_paren
|
|
|
|
;
|
|
|
|
|
|
|
|
select_with_paren:
|
|
|
|
'(' select_no_paren ')' { $$ = $2; }
|
|
|
|
| '(' select_with_paren ')' { $$ = $2; }
|
|
|
|
;
|
|
|
|
|
|
|
|
select_no_paren:
|
|
|
|
select_clause opt_order opt_limit {
|
|
|
|
$$ = $1;
|
|
|
|
$$->order = $2;
|
|
|
|
$$->limit = $3;
|
|
|
|
}
|
2014-11-26 00:26:20 +01:00
|
|
|
| select_clause set_operator select_clause opt_order opt_limit {
|
|
|
|
// TODO: allow multiple unions (through linked list)
|
|
|
|
// TODO: capture type of set_operator
|
|
|
|
// TODO: might overwrite order and limit of first select here
|
2014-11-13 01:27:47 +01:00
|
|
|
$$ = $1;
|
|
|
|
$$->union_select = $3;
|
|
|
|
$$->order = $4;
|
|
|
|
$$->limit = $5;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2014-11-26 00:26:20 +01:00
|
|
|
set_operator:
|
|
|
|
UNION
|
|
|
|
| INTERSECT
|
|
|
|
| EXCEPT
|
2014-11-13 01:27:47 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
select_clause:
|
2014-12-18 12:28:24 +01:00
|
|
|
SELECT opt_distinct select_list from_clause opt_where opt_group {
|
2014-11-13 01:27:47 +01:00
|
|
|
$$ = new SelectStatement();
|
2014-12-18 12:28:24 +01:00
|
|
|
$$->select_distinct = $2;
|
|
|
|
$$->select_list = $3;
|
|
|
|
$$->from_table = $4;
|
|
|
|
$$->where_clause = $5;
|
|
|
|
$$->group_by = $6;
|
2014-10-09 02:55:07 +02:00
|
|
|
}
|
2014-11-07 01:09:06 +01:00
|
|
|
;
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-12-18 12:28:24 +01:00
|
|
|
opt_distinct:
|
|
|
|
DISTINCT { $$ = true; }
|
|
|
|
| /* empty */ { $$ = false; }
|
|
|
|
;
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-10-22 17:18:43 +02:00
|
|
|
select_list:
|
2014-10-24 16:10:38 +02:00
|
|
|
expr_list
|
|
|
|
;
|
2014-10-22 17:18:43 +02:00
|
|
|
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-10-09 02:55:07 +02:00
|
|
|
from_clause:
|
2014-10-23 18:12:03 +02:00
|
|
|
FROM table_ref { $$ = $2; }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-10-22 15:43:27 +02:00
|
|
|
|
2014-11-13 01:27:47 +01:00
|
|
|
opt_where:
|
2014-10-24 16:10:38 +02:00
|
|
|
WHERE expr { $$ = $2; }
|
2014-10-09 04:46:25 +02:00
|
|
|
| /* empty */ { $$ = NULL; }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
|
|
|
|
2014-11-13 01:27:47 +01:00
|
|
|
opt_group:
|
2014-12-18 12:11:26 +01:00
|
|
|
GROUP BY expr_list opt_having {
|
|
|
|
$$ = new GroupByDescription();
|
|
|
|
$$->columns = $3;
|
|
|
|
$$->having = $4;
|
|
|
|
}
|
2014-10-09 02:55:07 +02:00
|
|
|
| /* empty */ { $$ = NULL; }
|
|
|
|
;
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-12-18 12:11:26 +01:00
|
|
|
opt_having:
|
|
|
|
HAVING expr { $$ = $2; }
|
|
|
|
| /* empty */ { $$ = NULL; }
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-11-13 01:27:47 +01:00
|
|
|
opt_order:
|
|
|
|
ORDER BY expr opt_order_type { $$ = new OrderDescription($4, $3); }
|
2014-10-27 14:54:15 +01:00
|
|
|
| /* empty */ { $$ = NULL; }
|
2014-11-07 01:09:06 +01:00
|
|
|
;
|
2014-10-27 14:54:15 +01:00
|
|
|
|
2014-11-13 01:27:47 +01:00
|
|
|
opt_order_type:
|
2014-10-27 14:54:15 +01:00
|
|
|
ASC { $$ = kOrderAsc; }
|
|
|
|
| DESC { $$ = kOrderDesc; }
|
|
|
|
| /* empty */ { $$ = kOrderAsc; }
|
2014-11-07 01:09:06 +01:00
|
|
|
;
|
2014-10-27 14:54:15 +01:00
|
|
|
|
2014-11-13 01:27:47 +01:00
|
|
|
|
|
|
|
opt_limit:
|
2014-10-27 14:54:15 +01:00
|
|
|
LIMIT int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
|
2014-11-13 01:27:47 +01:00
|
|
|
| LIMIT int_literal OFFSET int_literal { $$ = new LimitDescription($2->ival, $4->ival); delete $2; delete $4; }
|
2014-10-27 14:54:15 +01:00
|
|
|
| /* empty */ { $$ = NULL; }
|
2014-11-07 01:09:06 +01:00
|
|
|
;
|
2014-10-27 14:54:15 +01:00
|
|
|
|
2014-10-24 16:10:38 +02:00
|
|
|
/******************************
|
2014-11-26 14:43:22 +01:00
|
|
|
* Expressions
|
2014-10-24 16:10:38 +02:00
|
|
|
******************************/
|
|
|
|
expr_list:
|
2015-01-06 19:47:59 +01:00
|
|
|
expr_alias { $$ = new std::vector<Expr*>(); $$->push_back($1); }
|
2014-11-12 10:43:10 +01:00
|
|
|
| expr_list ',' expr_alias { $1->push_back($3); $$ = $1; }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
|
|
|
|
2014-11-26 00:26:20 +01:00
|
|
|
literal_list:
|
2015-01-06 19:47:59 +01:00
|
|
|
literal { $$ = new std::vector<Expr*>(); $$->push_back($1); }
|
2014-11-26 00:26:20 +01:00
|
|
|
| literal_list ',' literal { $1->push_back($3); $$ = $1; }
|
|
|
|
;
|
|
|
|
|
2014-11-12 10:43:10 +01:00
|
|
|
expr_alias:
|
|
|
|
expr opt_alias {
|
|
|
|
$$ = $1;
|
|
|
|
$$->alias = $2;
|
|
|
|
}
|
|
|
|
;
|
2014-10-22 15:43:27 +02:00
|
|
|
|
2014-10-24 16:10:38 +02:00
|
|
|
expr:
|
|
|
|
'(' expr ')' { $$ = $2; }
|
|
|
|
| scalar_expr
|
|
|
|
| unary_expr
|
|
|
|
| binary_expr
|
|
|
|
| function_expr
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-10-24 16:10:38 +02:00
|
|
|
scalar_expr:
|
|
|
|
column_name
|
|
|
|
| star_expr
|
|
|
|
| literal
|
|
|
|
;
|
2014-10-22 15:43:27 +02:00
|
|
|
|
2014-10-24 16:10:38 +02:00
|
|
|
unary_expr:
|
2014-10-31 18:05:08 +01:00
|
|
|
'-' expr { $$ = Expr::makeOpUnary(Expr::UMINUS, $2); }
|
|
|
|
| NOT expr { $$ = Expr::makeOpUnary(Expr::NOT, $2); }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
2014-10-09 01:30:22 +02:00
|
|
|
|
2014-10-24 16:10:38 +02:00
|
|
|
binary_expr:
|
|
|
|
comp_expr
|
2014-11-05 15:54:41 +01:00
|
|
|
| expr '-' expr { $$ = Expr::makeOpBinary($1, '-', $3); }
|
|
|
|
| expr '+' expr { $$ = Expr::makeOpBinary($1, '+', $3); }
|
|
|
|
| expr '/' expr { $$ = Expr::makeOpBinary($1, '/', $3); }
|
|
|
|
| expr '*' expr { $$ = Expr::makeOpBinary($1, '*', $3); }
|
2014-11-07 16:29:46 +01:00
|
|
|
| expr '%' expr { $$ = Expr::makeOpBinary($1, '%', $3); }
|
|
|
|
| expr '^' expr { $$ = Expr::makeOpBinary($1, '^', $3); }
|
2014-11-05 15:54:41 +01:00
|
|
|
| expr AND expr { $$ = Expr::makeOpBinary($1, Expr::AND, $3); }
|
|
|
|
| expr OR expr { $$ = Expr::makeOpBinary($1, Expr::OR, $3); }
|
|
|
|
| expr LIKE expr { $$ = Expr::makeOpBinary($1, Expr::LIKE, $3); }
|
|
|
|
| expr NOT LIKE expr { $$ = Expr::makeOpBinary($1, Expr::NOT_LIKE, $4); }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
|
2014-10-24 16:10:38 +02:00
|
|
|
comp_expr:
|
2014-11-07 16:29:46 +01:00
|
|
|
expr '=' expr { $$ = Expr::makeOpBinary($1, '=', $3); }
|
2014-11-05 15:54:41 +01:00
|
|
|
| expr NOTEQUALS expr { $$ = Expr::makeOpBinary($1, Expr::NOT_EQUALS, $3); }
|
2014-11-07 16:29:46 +01:00
|
|
|
| expr '<' expr { $$ = Expr::makeOpBinary($1, '<', $3); }
|
|
|
|
| expr '>' expr { $$ = Expr::makeOpBinary($1, '>', $3); }
|
2014-11-05 15:54:41 +01:00
|
|
|
| expr LESSEQ expr { $$ = Expr::makeOpBinary($1, Expr::LESS_EQ, $3); }
|
|
|
|
| expr GREATEREQ expr { $$ = Expr::makeOpBinary($1, Expr::GREATER_EQ, $3); }
|
2014-10-24 16:10:38 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
function_expr:
|
2014-12-18 12:28:24 +01:00
|
|
|
IDENTIFIER '(' opt_distinct expr ')' { $$ = Expr::makeFunctionRef($1, $4, $3); }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
column_name:
|
2014-11-12 10:43:10 +01:00
|
|
|
IDENTIFIER { $$ = Expr::makeColumnRef($1); }
|
|
|
|
| IDENTIFIER '.' IDENTIFIER { $$ = Expr::makeColumnRef($1, $3); }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
literal:
|
2014-11-07 02:00:09 +01:00
|
|
|
string_literal
|
2014-10-27 14:54:15 +01:00
|
|
|
| num_literal
|
2014-12-15 15:01:01 +01:00
|
|
|
| placeholder_expr
|
2014-10-27 14:54:15 +01:00
|
|
|
;
|
|
|
|
|
2014-11-07 02:00:09 +01:00
|
|
|
string_literal:
|
|
|
|
STRING { $$ = Expr::makeLiteral($1); }
|
|
|
|
;
|
|
|
|
|
|
|
|
|
2014-10-27 14:54:15 +01:00
|
|
|
num_literal:
|
2014-12-03 16:32:56 +01:00
|
|
|
FLOATVAL { $$ = Expr::makeLiteral($1); }
|
2014-10-27 14:54:15 +01:00
|
|
|
| int_literal
|
|
|
|
;
|
|
|
|
|
|
|
|
int_literal:
|
2014-12-03 16:32:56 +01:00
|
|
|
INTVAL { $$ = Expr::makeLiteral($1); }
|
2014-10-09 02:55:07 +02:00
|
|
|
;
|
|
|
|
|
2014-10-24 16:10:38 +02:00
|
|
|
star_expr:
|
2014-10-27 11:23:31 +01:00
|
|
|
'*' { $$ = new Expr(kExprStar); }
|
2014-10-22 15:43:27 +02:00
|
|
|
;
|
|
|
|
|
2015-01-06 20:01:10 +01:00
|
|
|
|
2014-12-15 15:01:01 +01:00
|
|
|
placeholder_expr:
|
2015-01-06 15:29:18 +01:00
|
|
|
'?' {
|
|
|
|
$$ = Expr::makePlaceholder(yylloc.total_column);
|
|
|
|
yyloc.placeholder_list.push_back($$);
|
|
|
|
}
|
2014-12-15 15:01:01 +01:00
|
|
|
;
|
|
|
|
|
2014-10-23 18:12:03 +02:00
|
|
|
|
|
|
|
/******************************
|
2014-11-26 14:43:22 +01:00
|
|
|
* Table
|
2014-10-23 18:12:03 +02:00
|
|
|
******************************/
|
|
|
|
table_ref:
|
|
|
|
table_ref_atomic
|
|
|
|
| table_ref_atomic ',' table_ref_commalist {
|
2014-11-04 10:05:09 +01:00
|
|
|
$3->push_back($1);
|
|
|
|
auto tbl = new TableRef(kTableCrossProduct);
|
|
|
|
tbl->list = $3;
|
|
|
|
$$ = tbl;
|
|
|
|
}
|
2014-10-23 18:12:03 +02:00
|
|
|
;
|
|
|
|
|
2014-11-04 01:42:09 +01:00
|
|
|
|
2014-10-23 18:12:03 +02:00
|
|
|
table_ref_atomic:
|
2014-11-04 01:42:09 +01:00
|
|
|
table_ref_name
|
|
|
|
| '(' select_statement ')' alias {
|
2014-10-27 11:23:31 +01:00
|
|
|
auto tbl = new TableRef(kTableSelect);
|
2014-10-27 12:09:53 +01:00
|
|
|
tbl->select = $2;
|
2014-11-04 01:42:09 +01:00
|
|
|
tbl->alias = $4;
|
2014-10-23 18:12:03 +02:00
|
|
|
$$ = tbl;
|
|
|
|
}
|
2014-11-07 01:09:06 +01:00
|
|
|
| join_clause
|
2014-10-23 18:12:03 +02:00
|
|
|
;
|
|
|
|
|
2014-11-03 23:57:42 +01:00
|
|
|
|
2014-10-22 15:43:27 +02:00
|
|
|
table_ref_commalist:
|
2015-01-06 19:47:59 +01:00
|
|
|
table_ref_atomic { $$ = new std::vector<TableRef*>(); $$->push_back($1); }
|
2014-10-23 18:12:03 +02:00
|
|
|
| table_ref_commalist ',' table_ref_atomic { $1->push_back($3); $$ = $1; }
|
2014-10-22 15:43:27 +02:00
|
|
|
;
|
|
|
|
|
2014-11-03 23:57:42 +01:00
|
|
|
|
2014-11-04 01:42:09 +01:00
|
|
|
table_ref_name:
|
|
|
|
table_name opt_alias {
|
|
|
|
auto tbl = new TableRef(kTableName);
|
|
|
|
tbl->name = $1;
|
|
|
|
tbl->alias = $2;
|
2014-11-03 23:57:42 +01:00
|
|
|
$$ = tbl;
|
|
|
|
}
|
2014-12-02 01:27:02 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
table_ref_name_no_alias:
|
|
|
|
table_name {
|
|
|
|
$$ = new TableRef(kTableName);
|
|
|
|
$$->name = $1;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2014-11-03 23:57:42 +01:00
|
|
|
|
2014-10-23 18:12:03 +02:00
|
|
|
table_name:
|
2014-11-12 10:43:10 +01:00
|
|
|
IDENTIFIER
|
|
|
|
| IDENTIFIER '.' IDENTIFIER
|
2014-10-23 18:12:03 +02:00
|
|
|
;
|
2014-10-22 15:43:27 +02:00
|
|
|
|
|
|
|
|
2014-11-04 01:42:09 +01:00
|
|
|
alias:
|
2014-11-12 10:43:10 +01:00
|
|
|
AS IDENTIFIER { $$ = $2; }
|
|
|
|
| IDENTIFIER
|
2014-11-04 01:42:09 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
opt_alias:
|
|
|
|
alias
|
|
|
|
| /* empty */ { $$ = NULL; }
|
2014-10-24 16:10:38 +02:00
|
|
|
|
2014-11-04 10:05:09 +01:00
|
|
|
|
|
|
|
/******************************
|
2014-11-26 14:43:22 +01:00
|
|
|
* Join Statements
|
2014-11-04 10:05:09 +01:00
|
|
|
******************************/
|
|
|
|
|
2014-11-07 01:09:06 +01:00
|
|
|
join_clause:
|
2014-11-18 16:38:31 +01:00
|
|
|
join_table opt_join_type JOIN join_table ON join_condition
|
2014-11-04 10:05:09 +01:00
|
|
|
{
|
|
|
|
$$ = new TableRef(kTableJoin);
|
2014-11-17 22:13:11 +01:00
|
|
|
$$->join = new JoinDefinition();
|
|
|
|
$$->join->type = (JoinType) $2;
|
|
|
|
$$->join->left = $1;
|
2014-11-18 16:38:31 +01:00
|
|
|
$$->join->right = $4;
|
|
|
|
$$->join->condition = $6;
|
2014-11-04 10:05:09 +01:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2014-11-17 22:13:11 +01:00
|
|
|
opt_join_type:
|
|
|
|
INNER { $$ = kJoinInner; }
|
|
|
|
| OUTER { $$ = kJoinOuter; }
|
|
|
|
| LEFT { $$ = kJoinLeft; }
|
|
|
|
| RIGHT { $$ = kJoinRight; }
|
|
|
|
| /* empty, default */ { $$ = kJoinInner; }
|
|
|
|
;
|
|
|
|
|
|
|
|
|
2014-11-04 10:05:09 +01:00
|
|
|
|
|
|
|
join_table:
|
|
|
|
'(' select_statement ')' alias {
|
|
|
|
auto tbl = new TableRef(kTableSelect);
|
|
|
|
tbl->select = $2;
|
|
|
|
tbl->alias = $4;
|
|
|
|
$$ = tbl;
|
|
|
|
}
|
|
|
|
| table_ref_name;
|
|
|
|
|
|
|
|
|
|
|
|
join_condition:
|
|
|
|
expr
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
/******************************
|
2014-11-26 14:43:22 +01:00
|
|
|
* Misc
|
2014-11-04 10:05:09 +01:00
|
|
|
******************************/
|
|
|
|
|
2014-10-24 16:10:38 +02:00
|
|
|
opt_semicolon:
|
|
|
|
';'
|
|
|
|
| /* empty */
|
|
|
|
;
|
|
|
|
|
|
|
|
|
2014-11-26 00:26:20 +01:00
|
|
|
ident_commalist:
|
2015-01-06 19:47:59 +01:00
|
|
|
IDENTIFIER { $$ = new std::vector<char*>(); $$->push_back($1); }
|
2014-11-26 00:26:20 +01:00
|
|
|
| ident_commalist ',' IDENTIFIER { $1->push_back($3); $$ = $1; }
|
|
|
|
;
|
|
|
|
|
2014-10-20 22:33:36 +02:00
|
|
|
%%
|
2014-10-22 15:43:27 +02:00
|
|
|
/*********************************
|
|
|
|
** Section 4: Additional C code
|
|
|
|
*********************************/
|
|
|
|
|
|
|
|
/* empty */
|
|
|
|
|