Index: MultiSource/Applications/CMakeLists.txt
===================================================================
--- MultiSource/Applications/CMakeLists.txt
+++ MultiSource/Applications/CMakeLists.txt
@@ -20,7 +20,7 @@
llvm_add_subdirectories(SPASS)
endif()
if(NOT ARCH STREQUAL "XCore")
- llvm_add_subdirectories(siod ClamAV lemon)
+ llvm_add_subdirectories(siod ClamAV)
endif()
if((NOT ARCH STREQUAL "PowerPC") AND (NOT ARCH STREQUAL "XCore"))
llvm_add_subdirectories(sqlite3)
Index: MultiSource/Applications/Makefile
===================================================================
--- MultiSource/Applications/Makefile
+++ MultiSource/Applications/Makefile
@@ -5,7 +5,7 @@
include $(LEVEL)/Makefile.config
PARALLEL_DIRS = Burg aha sgefa siod d spiff treecc SPASS \
- oggenc JM viterbi SIBsim4 ClamAV sqlite3 lemon
+ oggenc JM viterbi SIBsim4 ClamAV sqlite3
ifndef DISABLE_CXX
PARALLEL_DIRS += lambda-0.1.3 hbd hexxagon minisat ALAC
endif
@@ -37,9 +37,6 @@
PARALLEL_DIRS := $(filter-out ClamAV, $(PARALLEL_DIRS))
PARALLEL_DIRS := $(filter-out sqlite3, $(PARALLEL_DIRS))
PARALLEL_DIRS := $(filter-out obsequi, $(PARALLEL_DIRS))
-# XCore does not support fork().
-# lemon removed pending general method for running tests multiple times.
-PARALLEL_DIRS := $(filter-out lemon, $(PARALLEL_DIRS))
endif
ifdef BENCHMARKING_ONLY
Index: MultiSource/Applications/lemon/CMakeLists.txt
===================================================================
--- MultiSource/Applications/lemon/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(Source lemon.c)
-set(PROG lemon)
-set(RUN_OPTIONS ${CMAKE_CURRENT_SOURCE_DIR}/parse.y ${CMAKE_CURRENT_SOURCE_DIR}/example1.y ${CMAKE_CURRENT_SOURCE_DIR}/example2.y ${CMAKE_CURRENT_SOURCE_DIR}/example3.y ${CMAKE_CURRENT_SOURCE_DIR}/example4.y ${CMAKE_CURRENT_SOURCE_DIR}/example5.y ${CMAKE_CURRENT_SOURCE_DIR}/lighttpd_configparser.y ${CMAKE_CURRENT_SOURCE_DIR}/lighttpd_mod_ssi_exprparser.y ${CMAKE_CURRENT_SOURCE_DIR}/wireshark_dtd_grammar.lemon ${CMAKE_CURRENT_SOURCE_DIR}/wireshark_grammar.lemon ${CMAKE_CURRENT_SOURCE_DIR}/wireshark_mate_grammar.lemon ${CMAKE_CURRENT_SOURCE_DIR}/xapian_queryparser.lemony ${CMAKE_CURRENT_SOURCE_DIR}/ecmascript.y)
-set(HASH_PROGRAM_OUTPUT 1)
-set(RUNTIMELIMIT 1500)
-set(DIFFPROG ${PROGDIR}/DiffOutput.sh "diff ")
-llvm_multisource()
Index: MultiSource/Applications/lemon/Makefile
===================================================================
--- MultiSource/Applications/lemon/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-LEVEL = ../../../
-
-Source = lemon.c
-
-PROG = lemon
-RUN_OPTIONS = $(PROJ_SRC_DIR)/parse.y $(PROJ_SRC_DIR)/example1.y $(PROJ_SRC_DIR)/example2.y $(PROJ_SRC_DIR)/example3.y $(PROJ_SRC_DIR)/example4.y $(PROJ_SRC_DIR)/example5.y $(PROJ_SRC_DIR)/lighttpd_configparser.y $(PROJ_SRC_DIR)/lighttpd_mod_ssi_exprparser.y $(PROJ_SRC_DIR)/wireshark_dtd_grammar.lemon $(PROJ_SRC_DIR)/wireshark_grammar.lemon $(PROJ_SRC_DIR)/wireshark_mate_grammar.lemon $(PROJ_SRC_DIR)/xapian_queryparser.lemony $(PROJ_SRC_DIR)/ecmascript.y
-HASH_PROGRAM_OUTPUT = 1
-
-# With a Debug+Asserts build may time out if the default limit is used.
-RUNTIMELIMIT := 1500
-
-include $(LEVEL)/Makefile.config
-
-include ../../Makefile.multisrc
-DIFFPROG := $(PROGDIR)/DiffOutput.sh "diff "
-
Index: MultiSource/Applications/lemon/README
===================================================================
--- MultiSource/Applications/lemon/README
+++ /dev/null
@@ -1,13 +0,0 @@
-lemon.c, lempar.c, parse.y are from SQLite3, which is in the public domain (copyright-release.html)
-
-Homepage of lemon is http://www.hwaci.com/sw/lemon/lemon.html
-
-example[1-5].y is from the Lemon Parser Tutorial, covered by example_COPYING http://sourceforge.net/project/showfiles.php?group_id=79320&package_id=124528
-
-lighttpd_mod_ssi_exprparser.y, and lighttpd_configparser.y is from lighttpd-1.4.19,
-covered by lighttpd_COPYING
-
-wireshark_grammar.lemon, wireshark_dtd_grammar.lemon, wireshark_mate_grammar.lemon is from wireshark-0.99.8, covered by wireshark_COPYING
-
-xapian_queryparser.lemony is from xapian-core-1.0.5, covered by xapian_COPYING
-
Index: MultiSource/Applications/lemon/copyright-release.html
===================================================================
--- MultiSource/Applications/lemon/copyright-release.html
+++ /dev/null
@@ -1,109 +0,0 @@
-
-
-
-Copyright Release for
-Contributions To SQLite
-
-
-
-SQLite is software that implements an embeddable SQL database engine.
-SQLite is available for free download from http://www.sqlite.org/.
-The principal author and maintainer of SQLite has disclaimed all
-copyright interest in his contributions to SQLite
-and thus released his contributions into the public domain.
-In order to keep the SQLite software unencumbered by copyright
-claims, the principal author asks others who may from time to
-time contribute changes and enhancements to likewise disclaim
-their own individual copyright interest.
-
-
-
-Because the SQLite software found at http://www.sqlite.org/ is in the
-public domain, anyone is free to download the SQLite software
-from that website, make changes to the software, use, distribute,
-or sell the modified software, under either the original name or
-under some new name, without any need to obtain permission, pay
-royalties, acknowledge the original source of the software, or
-in any other way compensate, identify, or notify the original authors.
-Nobody is in any way compelled to contribute their SQLite changes and
-enhancements back to the SQLite website. This document concerns
-only changes and enhancements to SQLite that are intentionally and
-deliberately contributed back to the SQLite website.
-
-
-
-For the purposes of this document, "SQLite software" shall mean any
-computer source code, documentation, makefiles, test scripts, or
-other information that is published on the SQLite website,
-http://www.sqlite.org/. Precompiled binaries are excluded from
-the definition of "SQLite software" in this document because the
-process of compiling the software may introduce information from
-outside sources which is not properly a part of SQLite.
-
-
-
-The header comments on the SQLite source files exhort the reader to
-share freely and to never take more than one gives.
-In the spirit of that exhortation I make the following declarations:
-
-
-
-
-I dedicate to the public domain
-any and all copyright interest in the SQLite software that
-was publicly available on the SQLite website (http://www.sqlite.org/) prior
-to the date of the signature below and any changes or enhancements to
-the SQLite software
-that I may cause to be published on that website in the future.
-I make this dedication for the benefit of the public at large and
-to the detriment of my heirs and successors. I intend this
-dedication to be an overt act of relinquishment in perpetuity of
-all present and future rights to the SQLite software under copyright
-law.
-
-
-
-To the best of my knowledge and belief, the changes and enhancements that
-I have contributed to SQLite are either originally written by me
-or are derived from prior works which I have verified are also
-in the public domain and are not subject to claims of copyright
-by other parties.
-
-
-
-To the best of my knowledge and belief, no individual, business, organization,
-government, or other entity has any copyright interest
-in the SQLite software as it existed on the
-SQLite website as of the date on the signature line below.
-
-
-
-I agree never to publish any additional information
-to the SQLite website (by CVS, email, scp, FTP, or any other means) unless
-that information is an original work of authorship by me or is derived from
-prior published versions of SQLite.
-I agree never to copy and paste code into the SQLite code base from
-other sources.
-I agree never to publish on the SQLite website any information that
-would violate a law or breach a contract.
-
-
-
-
-
-
-
-Signature:
-
-
-
- |
-Date:
- |
-
-Name (printed):
- |
-
-
-
-
Index: MultiSource/Applications/lemon/ecmascript.y
===================================================================
--- MultiSource/Applications/lemon/ecmascript.y
+++ /dev/null
@@ -1,270 +0,0 @@
-%include {
-#include
-#include
-#include "lexglobal.h"
-}
-%token_type{int}
-%nonassoc PRECEDENCE_KEYWORD PRECEDENCE_IDENTIFIER.
-
-program ::= source_elements.
-
-
-
-identifier ::= IDENTIFIER_NAME. [PRECEDENCE_IDENTIFIER]
-
-
-
-literal ::= NULL_LITERAL.
-literal ::= BOOLEAN_LITERAL.
-literal ::= NumericLiteral.
-literal ::= StringLiteral.
-
-primary_expression ::= THIS.
-primary_expression ::= identifier.
-primary_expression ::= literal.
-primary_expression ::= array_literal.
-primary_expression ::= object_literal.
-primary_expression ::= PAR_OPEN expression PAR_CLOSE.
-
-elision_opt ::= .
-elision_opt ::= elision.
-
-array_literal ::= BRACKET_OPEN elision_opt BRACKET_CLOSE
- |BRACKET_OPEN element_list BRACKET_CLOSE
- |BRACKET_OPEN element_list COMMA elision_opt BRACKET_CLOSE.
-
-assignment_operator ::= EQUAL.
-assignment_operator ::= ASSIGNMENT_OPERATOR_NOEQUAL.
-
-elision ::= COMMA.
-elision ::= elision COMMA.
-
-element_list ::= elision_opt assignment_expression.
-element_list ::= element_list COMMA elision_opt COMMA assignment_expression.
-
-object_literal ::= CURLY_BRACE_OPEN CURLY_BRACE_CLOSE
- |CURLY_BRACE_OPEN property_name_and_value_list CURLY_BRACE_CLOSE.
-
-property_name_and_value_list ::= property_name COLON assignment_expression.
-property_name_and_value_list ::= property_name_and_value_list COMMA property_name COLON assignment_expression.
-
-property_name ::= identifier.
-property_name ::= StringLiteral
- |NumericLiteral.
-
-
-/*
-
-temp phony decls
-
-*/
-
-function_expression ::= .
-/*------------------*/
-member_expression ::= primary_expression.
-member_expression ::= function_expression.
-member_expression ::= member_expression BRACKET_OPEN expression BRACKET_CLOSE.
-member_expression ::= member_expression DOT identifier.
-member_expression ::= NEW member_expression arguments.
-
-new_expression ::= member_expression.
-new_expression ::= NEW new_expression.
-
-call_expression ::= member_expression arguments.
-call_expression ::= call_expression arguments.
-call_expression ::= call_expression BRACKET_OPEN expression BRACKET_CLOSE.
-call_expression ::= call_expression DOT identifier.
-
-arguments ::= PAR_OPEN PAR_CLOSE
- |PAR_OPEN arguments_list PAR_CLOSE.
-
-arguments_list ::= assignment_expression.
-arguments_list ::= arguments_list COMMA assignment_expression.
-
-lefthandside_expression ::= new_expression.
-lefthandside_expression ::= call_expression.
-
-postfix_expression ::= lefthandside_expression.
-postfix_expression ::= lefthandside_expression NOLF_PLUSPLUS.
-postfix_expression ::= lefthandside_expression NOLF_MINUSMINUS.
-
-unary_expression ::= postfix_expression.
-unary_expression ::= DELETE|VOID|TYPEOF|PLUSPLUS|MINUSMINUS|MINUS|TILDE|EXCLAMATION unary_expression.
-
-multiplicative_expression ::= unary_expression.
-multiplicative_expression ::= multiplicative_expression MULTIPLY|DIVIDE|PERCENT unary_expression.
-
-additive_expression ::= multiplicative_expression.
-additive_expression ::= additive_expression PLUS|MINUS multiplicative_expression.
-
-shift_expression ::= additive_expression.
-shift_expression ::= shift_expression SHIFT_LEFT|SHIFT_RIGHT|DOUBLESHIFT_RIGHT additive_expression.
-
-relational_expression ::= shift_expression.
-relational_expression ::= relational_expression LESS|GREATER|LESSEQUAL|GREATEREQUAL|INSTANCEOF|IN shift_expression.
-
-relational_expression_noin ::= shift_expression.
-relational_expression_noin ::= relational_expression LESS|GREATER|LESSEQUAL|GREATEREQUAL|INSTANCEOF shift_expression.
-
-equality_expression ::= relational_expression.
-equality_expression ::= equality_expression EQUAL_EQUAL|NOT_EQUAL|TRIPLE_EQUAL|NOT_DOUBLEEQUAL relational_expression.
-
-equality_expression_noin ::= relational_expression_noin.
-equality_expression_noin ::= equality_expression_noin EQUAL_EQUAL|NOT_EQUAL|TRIPLE_EQUAL|NOT_DOUBLEEQUAL relational_expression_noin.
-
-bitwise_and_expression ::= equality_expression.
-bitwise_and_expression ::= bitwise_and_expression AND equality_expression.
-
-bitwise_and_expression_noin ::= equality_expression_noin.
-bitwise_and_expression_noin ::= bitwise_and_expression_noin AND equality_expression_noin.
-
-bitwise_xor_expression ::= bitwise_and_expression.
-bitwise_xor_expression ::= bitwise_xor_expression XOR bitwise_and_expression.
-
-
-bitwise_xor_expression_noin ::= bitwise_and_expression_noin.
-bitwise_xor_expression_noin ::= bitwise_xor_expression_noin XOR bitwise_and_expression_noin.
-
-bitwise_or_expression ::= bitwise_xor_expression.
-bitwise_or_expression ::= bitwise_or_expression OR bitwise_xor_expression.
-
-
-bitwise_or_expression_noin ::= bitwise_xor_expression_noin.
-bitwise_or_expression_noin ::= bitwise_or_expression_noin OR bitwise_xor_expression_noin.
-
-logical_and_expression ::= bitwise_or_expression.
-logical_and_expression ::= logical_and_expression AND_AND bitwise_or_expression.
-
-logical_and_expression_noin ::= bitwise_or_expression_noin.
-logical_and_expression_noin ::= logical_and_expression_noin AND_AND bitwise_or_expression_noin.
-
-
-logical_or_expression ::= logical_and_expression.
-logical_or_expression ::= logical_or_expression OR_OR logical_and_expression.
-
-logical_or_expression_noin ::= logical_and_expression_noin.
-logical_or_expression_noin ::= logical_or_expression_noin OR_OR logical_and_expression_noin.
-
-conditional_expression ::= logical_or_expression.
-conditional_expression ::= logical_or_expression QUESTIONMARK assignment_expression COLON assignment_expression.
-
-conditional_expression_noin ::= logical_or_expression_noin.
-conditional_expression_noin ::= logical_or_expression_noin QUESTIONMARK assignment_expression_noin COLON assignment_expression_noin.
-
-assignment_expression ::= conditional_expression.
-assignment_expression ::= lefthandside_expression assignment_operator assignment_expression.
-
-assignment_expression_noin ::= conditional_expression_noin.
-assignment_expression_noin ::= lefthandside_expression assignment_operator assignment_expression_noin.
-
-expression ::= assignment_expression.
-expression ::= expression COMMA assignment_expression.
-expression_opt ::= expression.
-
-expression_noin_opt ::= expression.
-
-statement ::= block.
-statement ::= variable_statement.
-statement ::= empty_statement.
-statement ::= expression_statement.
-statement ::= if_statement.
-statement ::= iteration_statement.
-statement ::= continue_statement.
-statement ::= break_statement.
-statement ::= return_statement.
-statement ::= with_statement.
-statement ::= labelled_statement.
-statement ::= throw_statement.
-statement ::= try_statement.
-
-block ::= CURLY_BRACE_OPEN statement_list_opt CURLY_BRACE_CLOSE.
-
-statement_list_opt ::= .
-statement_list_opt ::= statement_list.
-
-statement_list ::= statement.
-statement_list ::= statement_list statement.
-
-variable_statement ::= VAR variable_declaration_list SEMICOLON.
-
-variable_declaration_list ::= variable_declaration.
-variable_declaration_list ::= variable_declaration_list COMMA variable_declaration.
-
-variable_declaration_list_noin ::= variable_declaration_noin.
-variable_declaration_list_noin ::= variable_declaration_list_noin COMMA variable_declaration_noin.
-
-variable_declaration ::= identifier initialiser_opt.
-
-variable_declaration_noin ::= identifier initialiser_noin_opt.
-
-initialiser_opt ::= .
-
-initialiser_noin_opt ::= .
-initialiser_noin_opt ::= initaliser_noin.
-
-initaliser_noin ::= EQUAL assignment_expression_noin.
-
-empty_statement ::= SEMICOLON.
-
-expression_statement ::= expression SEMICOLON.
- /*TODO:IMPLEMENT THIS RULE: lookahead not-contains {, function*/
-
-if_statement ::= IF PAR_OPEN expression PAR_CLOSE ELSE statement.
-if_statement ::= IF PAR_OPEN expression PAR_CLOSE statement.
-
-
-iteration_statement ::= DO statement WHILE PAR_OPEN expression PAR_CLOSE SEMICOLON.
-iteration_statement ::= WHILE PAR_OPEN expression PAR_CLOSE statement.
-iteration_statement ::= FOR PAR_OPEN expression_noin_opt SEMICOLON expression_opt SEMICOLON expression_opt PAR_CLOSE statement.
-iteration_statement ::= FOR PAR_OPEN VAR variable_declaration_list_noin SEMICOLON expression_opt SEMICOLON expression_opt PAR_CLOSE statement.
-iteration_statement ::= FOR PAR_OPEN lefthandside_expression IN expression PAR_CLOSE statement.
-iteration_statement ::= FOR PAR_OPEN VAR variable_declaration_noin IN expression PAR_CLOSE statement.
-
-continue_statement ::= CONTINUE_NOLF identifier_opt SEMICOLON.
-
-break_statement ::= BREAK_NOLF identifier_opt SEMICOLON.
-
-return_statement ::= RETURN_NOLF expression_opt SEMICOLON.
-
-with_statement ::= WITH PAR_OPEN expression PAR_CLOSE statement.
-
-
-
-
-
-
-labelled_statement ::= identifier COLON statement.
-
-throw_statement ::= THROW_NOLF expression SEMICOLON.
-
-try_statement ::= TRY block catch.
-try_statement ::= TRY block finally.
-try_statement ::= TRY block catch finally.
-
-catch ::= CATCH PAR_OPEN identifier PAR_CLOSE block.
-
-finally ::= FINALLY block.
-
-identifier_opt ::= .
-identifier_opt ::= identifier.
-
-function_declaration ::= FUNCTION identifier PAR_OPEN formal_parameter_list_opt PAR_CLOSE CURLY_BRACE_OPEN function_body CURLY_BRACE_CLOSE.
-
-function_expression ::= FUNCTION identifier_opt PAR_OPEN formal_parameter_list_opt PAR_CLOSE CURLY_BRACE_OPEN function_body CURLY_BRACE_CLOSE.
-
-formal_parameter_list_opt ::= .
-formal_parameter_list_opt ::= formal_parameter_list.
-
-formal_parameter_list ::= identifier.
-formal_parameter_list ::= formal_parameter_list COMMA identifier.
-
-function_body ::= source_elements.
-
-
-source_elements ::= source_element.
-source_elements ::= source_elements source_element.
-
-source_element ::= statement.
-source_element ::= function_declaration.
-
-
Index: MultiSource/Applications/lemon/example1.y
===================================================================
--- MultiSource/Applications/lemon/example1.y
+++ /dev/null
@@ -1,68 +0,0 @@
-/* Copyright (GPL) 2004 mchirico@users.sourceforge.net or mchirico@comcast.net
-
- Simple lemon parser example.
-
-
- $ ./lemon example1.y
-
- The above statement will create example1.c.
-
- The command below adds main and the
- necessary "Parse" calls to the
- end of this example1.c.
-
-
- $ cat <>example1.c
- int main()
- {
- void* pParser = ParseAlloc (malloc);
- Parse (pParser, INTEGER, 1);
- Parse (pParser, PLUS, 0);
- Parse (pParser, INTEGER, 2);
- Parse (pParser, 0, 0);
- ParseFree(pParser, free );
- }
- EOF
-
-
- $ g++ -o ex1 example1.c
- $ ./ex1
-
- See the Makefile, as most all of this is
- done automatically.
-
- Downloads:
- http://prdownloads.sourceforge.net/souptonuts/lemon_examples.tar.gz?download
-
-*/
-
-%token_type {int}
-
-%left PLUS MINUS.
-%left DIVIDE TIMES.
-
-%include {
-#include
-#include "example1.h"
-}
-
-%syntax_error {
- std::cout << "Syntax error!" << std::endl;
-}
-
-program ::= expr(A). { std::cout << "Result=" << A << std::endl; }
-
-expr(A) ::= expr(B) MINUS expr(C). { A = B - C; }
-expr(A) ::= expr(B) PLUS expr(C). { A = B + C; }
-expr(A) ::= expr(B) TIMES expr(C). { A = B * C; }
-expr(A) ::= expr(B) DIVIDE expr(C). {
-
- if(C != 0){
- A = B / C;
- }else{
- std::cout << "divide by zero" << std::endl;
- }
-} /* end of DIVIDE */
-
-expr(A) ::= INTEGER(B). { A = B; }
-
Index: MultiSource/Applications/lemon/example2.y
===================================================================
--- MultiSource/Applications/lemon/example2.y
+++ /dev/null
@@ -1,107 +0,0 @@
-/* Copyright (GPL) 2004 mchirico@users.sourceforge.net or mchirico@comcast.net
- Simple lemon parser example.
-
- Download:
- http://prdownloads.sourceforge.net/souptonuts/lemon_examples.tar.gz?download
-
-
- To compile this example see the Makefile. Or
- this is what is taking place.
-
- $ ./lemon example2.y
- $ cat main_part2 >> example2.c
- $ g++ -o ex2 -O2 -s -pipe example2.c
-
- Next, run ./ex2
-
- $ ./ex2
-
- Which will give the following output:
-
- Result.value=17 <---------------------------\
- Result.n=4 |
- Result.value=-9 |
- Result.n=4 |
- Result.value=78 |
- Result.n=10 |
- |
- Now looking at a section of main_part2 |
- we can see how 4 PLUS 13 in implemented. |
- |
- struct Token t0,t1; |
- struct Token mToken; |
- |
- t0.value=4; |
- t0.n=0; |
- |
- t1.value=13; |
- t1.n=0; |
- // Below 4 PLUS 14 ----------------- /
- Parse (pParser, NUM, t0);
- Parse (pParser, PLUS, t0);
- Parse (pParser, NUM, t1);
- Parse (pParser, 0, t0);
-
-
-
-
-
-
-
-
-
-*/
-
-%include {
-#include
-#include "ex2def.h"
-#include "example2.h"
-}
-
-
-%token_type {Token}
-%default_type {Token}
-
-
-%type expr {Token}
-%type NUM {Token}
-
-%left PLUS MINUS.
-%left DIVIDE TIMES.
-
-
-
-%syntax_error {
- std::cout << "Syntax error!" << std::endl;
-}
-
-program ::= expr(A). {
- std::cout << "Result.value=" << A.value << std::endl;
- std::cout << "Result.n=" << A.n << std::endl;
-
- }
-
-
-expr(A) ::= expr(B) MINUS expr(C). { A.value = B.value - C.value;
- A.n = B.n+1 + C.n+1;
- }
-
-expr(A) ::= expr(B) PLUS expr(C). { A.value = B.value + C.value;
- A.n = B.n+1 + C.n+1;
- }
-
-expr(A) ::= expr(B) TIMES expr(C). { A.value = B.value * C.value;
- A.n = B.n+1 + C.n+1;
-
- }
-expr(A) ::= expr(B) DIVIDE expr(C). {
-
- if(C.value != 0){
- A.value = B.value / C.value;
- A.n = B.n+1 + C.n+1;
- }else{
- std::cout << "divide by zero" << std::endl;
- }
-} /* end of DIVIDE */
-expr(A) ::= NUM(B). { A.value = B.value; A.n = B.n+1; }
-
Index: MultiSource/Applications/lemon/example3.y
===================================================================
--- MultiSource/Applications/lemon/example3.y
+++ /dev/null
@@ -1,100 +0,0 @@
-/* Copyright (GPL) 2004 mchirico@users.sourceforge.net or mchirico@comcast.net
- Simple lemon parser example.
-
-
- $ ./lemon example2.y
- $ cat main_part2 >> example2.c
- $ g++ -o ex2 -O2 -s -pipe example2.c
-
- Now, to run the example.
-
- $ ./ex2
-
- The output will be as follows:
-
-
- Result.value=17 <-------------------
- Result.n=4 |
- Result.value=-9 |
- Result.n=4 |
- Result.value=78 |
- Result.n=10 |
- |
- Take a look at main_part2 |
- |
- |
- t0.value=4; |
- t0.n=0; |
- |
- t1.value=13; |
- t1.n=0; |
- |
- //Note below is 4 PLUS 17 ------
- Parse (pParser, NUM, t0);
- Parse (pParser, PLUS, t0);
- Parse (pParser, NUM, t1);
- Parse (pParser, 0, t0);
-
-*/
-
-%include {
-#include
-#include "ex3def.h"
-#include "example3.h"
-
- void token_destructor(Token t)
- {
- std::cout << "In token_destructor t.value= " << t.value << std::endl;
- std::cout << "In token_destructor t.n= " << t.n << std::endl;
- }
-
-}
-
-%token_type {Token}
-%default_type {Token}
-%token_destructor { token_destructor($$); }
-
-%type expr {Token}
-%type id {Token}
-
-%left PLUS MINUS.
-%left DIVIDE TIMES.
-
-%parse_accept {
- printf("parsing complete!\n\n\n");
-}
-
-%syntax_error {
- std::cout << "Syntax error!" << std::endl;
-}
-
-program ::= expr(A). {
- std::cout << "Result.value=" << A.value << std::endl;
- std::cout << "Result.n=" << A.n << std::endl;
-
- }
-
-expr(A) ::= expr(B) MINUS expr(C). { A.value = B.value - C.value;
- A.n = B.n+1 + C.n+1;
- }
-
-expr(A) ::= expr(B) PLUS expr(C). { A.value = B.value + C.value;
- A.n = B.n+1 + C.n+1;
- }
-
-expr(A) ::= expr(B) TIMES expr(C). { A.value = B.value * C.value;
- A.n = B.n+1 + C.n+1;
-
- }
-expr(A) ::= expr(B) DIVIDE expr(C). {
-
- if(C.value != 0){
- A.value = B.value / C.value;
- A.n = B.n+1 + C.n+1;
- }else{
- std::cout << "divide by zero" << std::endl;
- }
-} /* end of DIVIDE */
-expr(A) ::= NUM(B). { A.value = B.value; A.n = B.n+1; }
-
-
Index: MultiSource/Applications/lemon/example4.y
===================================================================
--- MultiSource/Applications/lemon/example4.y
+++ /dev/null
@@ -1,87 +0,0 @@
-/* Copyright (GPL) 2004 mchirico@users.sourceforge.net or mchirico@comcast.net
- Simple lemon parser example.
-
-
- $ ./lemon example2.y
-
-
-
-*/
-
-%include {
-#include
-#include "ex4def.h"
-#include "example4.h"
-
-
- void token_destructor(Token t)
- {
- std::cout << "In token_destructor t.value= " << t.value << std::endl;
- std::cout << "In token_destructor t.n= " << t.n << std::endl;
- }
-
-
-}
-
-
-%token_type {Token}
-%default_type {Token}
-%token_destructor { token_destructor($$); }
-
-%type expr {Token}
-%type NUM {Token}
-
-
-
-
-%left PLUS MINUS.
-%left DIVIDE TIMES.
-
-%parse_accept {
- printf("parsing complete!\n\n\n");
-}
-
-
-%syntax_error {
- std::cout << "Syntax error!" << std::endl;
-}
-
-/* This is to terminate with a new line */
-main ::= in.
-in ::= .
-in ::= in state NEWLINE.
-
-
-
-state ::= expr(A). {
- std::cout << "Result.value=" << A.value << std::endl;
- std::cout << "Result.n=" << A.n << std::endl;
-
- }
-
-
-
-expr(A) ::= expr(B) MINUS expr(C). { A.value = B.value - C.value;
- A.n = B.n+1 + C.n+1;
- }
-
-expr(A) ::= expr(B) PLUS expr(C). { A.value = B.value + C.value;
- A.n = B.n+1 + C.n+1;
- }
-
-expr(A) ::= expr(B) TIMES expr(C). { A.value = B.value * C.value;
- A.n = B.n+1 + C.n+1;
-
- }
-expr(A) ::= expr(B) DIVIDE expr(C). {
-
- if(C.value != 0){
- A.value = B.value / C.value;
- A.n = B.n+1 + C.n+1;
- }else{
- std::cout << "divide by zero" << std::endl;
- }
-} /* end of DIVIDE */
-expr(A) ::= NUM(B). { A.value = B.value; A.n = B.n+1; }
-
-
Index: MultiSource/Applications/lemon/example5.y
===================================================================
--- MultiSource/Applications/lemon/example5.y
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Copyright (GPL) 2004 mchirico@users.sourceforge.net or mchirico@comcast.net
- Simple lemon parser example.
-
-
- $ ./lemon example2.y
-
-
-
-*/
-
-%include {
-#include
-#include "ex5def.h"
-#include "example5.h"
-#include
-#include
-#include
-#include
-#include
-#include "lexglobal.h"
-#define BUFS 1024
-
-
-
- void token_destructor(Token t)
- {
- std::cout << "In token_destructor t.value= " << t.value << std::endl;
- std::cout << "In token_destructor t.n= " << t.n << std::endl;
- }
-
-
-}
-
-
-%token_type {Token}
-%default_type {Token}
-%token_destructor { token_destructor($$); }
-
-%type expr {Token}
-%type id {Token}
-
-
-
-
-%left PLUS MINUS.
-%left DIVIDE TIMES.
-
-%parse_accept {
- printf("parsing complete!\n\n\n");
-}
-
-
-%syntax_error {
- std::cout << "Syntax error!" << std::endl;
-}
-
-/* This is to terminate with a new line */
-main ::= in.
-in ::= .
-in ::= in state NEWLINE.
-
-
-
-state ::= expr(A). {
- std::cout << "Result.value=" << A.value << std::endl;
- std::cout << "Result.n=" << A.n << std::endl;
-
- }
-
-
-
-expr(A) ::= expr(B) MINUS expr(C). { A.value = B.value - C.value;
- A.n = B.n+1 + C.n+1;
- }
-
-expr(A) ::= expr(B) PLUS expr(C). { A.value = B.value + C.value;
- A.n = B.n+1 + C.n+1;
- }
-
-expr(A) ::= expr(B) TIMES expr(C). { A.value = B.value * C.value;
- A.n = B.n+1 + C.n+1;
-
- }
-expr(A) ::= expr(B) DIVIDE expr(C). {
-
- if(C.value != 0){
- A.value = B.value / C.value;
- A.n = B.n+1 + C.n+1;
- }else{
- std::cout << "divide by zero" << std::endl;
- }
-} /* end of DIVIDE */
-expr(A) ::= NUM(B). { A.value = B.value; A.n = B.n+1; }
-
-
Index: MultiSource/Applications/lemon/example_COPYING
===================================================================
--- MultiSource/Applications/lemon/example_COPYING
+++ /dev/null
@@ -1,298 +0,0 @@
-Copyright (C) 2003 Mike Chirico mmc mchirico@users.sourceforge.net
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
Index: MultiSource/Applications/lemon/lemon.c
===================================================================
--- MultiSource/Applications/lemon/lemon.c
+++ /dev/null
@@ -1,4883 +0,0 @@
-/*
-** This file contains all sources (including headers) to the LEMON
-** LALR(1) parser generator. The sources have been combined into a
-** single file to make it easy to include LEMON in the source tree
-** and Makefile of another program.
-**
-** The author of this program disclaims copyright.
-*/
-#include
-#include
-#include
-#include
-#include
-#include
-
-#ifndef __WIN32__
-# if defined(_WIN32) || defined(WIN32)
-# define __WIN32__
-# endif
-#endif
-
-#ifdef __WIN32__
-extern int access();
-#else
-#include
-#endif
-
-/* #define PRIVATE static */
-#define PRIVATE
-
-#ifdef TEST
-#define MAXRHS 5 /* Set low to exercise exception code */
-#else
-#define MAXRHS 1000
-#endif
-
-static const char *mybasename(const char *str) {
- const char *base = strrchr(str, '/');
- return base ? base+1 : str;
-}
-
-static char *msort(char*,char**,int(*)(const char*,const char*));
-
-static struct action *Action_new(void);
-static struct action *Action_sort(struct action *);
-
-/********** From the file "build.h" ************************************/
-void FindRulePrecedences();
-void FindFirstSets();
-void FindStates();
-void FindLinks();
-void FindFollowSets();
-void FindActions();
-
-/********* From the file "configlist.h" *********************************/
-void Configlist_init(/* void */);
-struct config *Configlist_add(/* struct rule *, int */);
-struct config *Configlist_addbasis(/* struct rule *, int */);
-void Configlist_closure(/* void */);
-void Configlist_sort(/* void */);
-void Configlist_sortbasis(/* void */);
-struct config *Configlist_return(/* void */);
-struct config *Configlist_basis(/* void */);
-void Configlist_eat(/* struct config * */);
-void Configlist_reset(/* void */);
-
-/********* From the file "error.h" ***************************************/
-void ErrorMsg(const char *, int,const char *, ...);
-
-/****** From the file "option.h" ******************************************/
-struct s_options {
- enum { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR,
- OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR} type;
- char *label;
- char *arg;
- char *message;
-};
-int OptInit(/* char**,struct s_options*,FILE* */);
-int OptNArgs(/* void */);
-char *OptArg(/* int */);
-void OptErr(/* int */);
-void OptPrint(/* void */);
-
-/******** From the file "parse.h" *****************************************/
-void Parse(/* struct lemon *lemp */);
-
-/********* From the file "plink.h" ***************************************/
-struct plink *Plink_new(/* void */);
-void Plink_add(/* struct plink **, struct config * */);
-void Plink_copy(/* struct plink **, struct plink * */);
-void Plink_delete(/* struct plink * */);
-
-/********** From the file "report.h" *************************************/
-void Reprint(/* struct lemon * */);
-void ReportOutput(/* struct lemon * */);
-void ReportTable(/* struct lemon * */);
-void ReportHeader(/* struct lemon * */);
-void CompressTables(/* struct lemon * */);
-void ResortStates(/* struct lemon * */);
-
-/********** From the file "set.h" ****************************************/
-void SetSize(/* int N */); /* All sets will be of size N */
-char *SetNew(/* void */); /* A new set for element 0..N */
-void SetFree(/* char* */); /* Deallocate a set */
-
-int SetAdd(/* char*,int */); /* Add element to a set */
-int SetUnion(/* char *A,char *B */); /* A <- A U B, thru element N */
-
-#define SetFind(X,Y) (X[Y]) /* True if Y is in set X */
-
-/********** From the file "struct.h" *************************************/
-/*
-** Principal data structures for the LEMON parser generator.
-*/
-
-typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean;
-
-/* Symbols (terminals and nonterminals) of the grammar are stored
-** in the following: */
-struct symbol {
- char *name; /* Name of the symbol */
- int index; /* Index number for this symbol */
- enum {
- TERMINAL,
- NONTERMINAL,
- MULTITERMINAL
- } type; /* Symbols are all either TERMINALS or NTs */
- struct rule *rule; /* Linked list of rules of this (if an NT) */
- struct symbol *fallback; /* fallback token in case this token doesn't parse */
- int prec; /* Precedence if defined (-1 otherwise) */
- enum e_assoc {
- LEFT,
- RIGHT,
- NONE,
- UNK
- } assoc; /* Associativity if predecence is defined */
- char *firstset; /* First-set for all rules of this symbol */
- Boolean lambda; /* True if NT and can generate an empty string */
- int useCnt; /* Number of times used */
- char *destructor; /* Code which executes whenever this symbol is
- ** popped from the stack during error processing */
- int destructorln; /* Line number of destructor code */
- char *datatype; /* The data type of information held by this
- ** object. Only used if type==NONTERMINAL */
- int dtnum; /* The data type number. In the parser, the value
- ** stack is a union. The .yy%d element of this
- ** union is the correct data type for this object */
- /* The following fields are used by MULTITERMINALs only */
- int nsubsym; /* Number of constituent symbols in the MULTI */
- struct symbol **subsym; /* Array of constituent symbols */
-};
-
-/* Each production rule in the grammar is stored in the following
-** structure. */
-struct rule {
- struct symbol *lhs; /* Left-hand side of the rule */
- char *lhsalias; /* Alias for the LHS (NULL if none) */
- int lhsStart; /* True if left-hand side is the start symbol */
- int ruleline; /* Line number for the rule */
- int nrhs; /* Number of RHS symbols */
- struct symbol **rhs; /* The RHS symbols */
- char **rhsalias; /* An alias for each RHS symbol (NULL if none) */
- int line; /* Line number at which code begins */
- char *code; /* The code executed when this rule is reduced */
- struct symbol *precsym; /* Precedence symbol for this rule */
- int index; /* An index number for this rule */
- Boolean canReduce; /* True if this rule is ever reduced */
- struct rule *nextlhs; /* Next rule with the same LHS */
- struct rule *next; /* Next rule in the global list */
-};
-
-/* A configuration is a production rule of the grammar together with
-** a mark (dot) showing how much of that rule has been processed so far.
-** Configurations also contain a follow-set which is a list of terminal
-** symbols which are allowed to immediately follow the end of the rule.
-** Every configuration is recorded as an instance of the following: */
-struct config {
- struct rule *rp; /* The rule upon which the configuration is based */
- int dot; /* The parse point */
- char *fws; /* Follow-set for this configuration only */
- struct plink *fplp; /* Follow-set forward propagation links */
- struct plink *bplp; /* Follow-set backwards propagation links */
- struct state *stp; /* Pointer to state which contains this */
- enum {
- COMPLETE, /* The status is used during followset and */
- INCOMPLETE /* shift computations */
- } status;
- struct config *next; /* Next configuration in the state */
- struct config *bp; /* The next basis configuration */
-};
-
-/* Every shift or reduce operation is stored as one of the following */
-struct action {
- struct symbol *sp; /* The look-ahead symbol */
- enum e_action {
- SHIFT,
- ACCEPT,
- REDUCE,
- ERROR,
- SSCONFLICT, /* A shift/shift conflict */
- SRCONFLICT, /* Was a reduce, but part of a conflict */
- RRCONFLICT, /* Was a reduce, but part of a conflict */
- SH_RESOLVED, /* Was a shift. Precedence resolved conflict */
- RD_RESOLVED, /* Was reduce. Precedence resolved conflict */
- NOT_USED /* Deleted by compression */
- } type;
- union {
- struct state *stp; /* The new state, if a shift */
- struct rule *rp; /* The rule, if a reduce */
- } x;
- struct action *next; /* Next action for this state */
- struct action *collide; /* Next action with the same hash */
-};
-
-/* Each state of the generated parser's finite state machine
-** is encoded as an instance of the following structure. */
-struct state {
- struct config *bp; /* The basis configurations for this state */
- struct config *cfp; /* All configurations in this set */
- int statenum; /* Sequencial number for this state */
- struct action *ap; /* Array of actions for this state */
- int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */
- int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */
- int iDflt; /* Default action */
-};
-#define NO_OFFSET (-2147483647)
-
-/* A followset propagation link indicates that the contents of one
-** configuration followset should be propagated to another whenever
-** the first changes. */
-struct plink {
- struct config *cfp; /* The configuration to which linked */
- struct plink *next; /* The next propagate link */
-};
-
-/* The state vector for the entire parser generator is recorded as
-** follows. (LEMON uses no global variables and makes little use of
-** static variables. Fields in the following structure can be thought
-** of as begin global variables in the program.) */
-struct lemon {
- struct state **sorted; /* Table of states sorted by state number */
- struct rule *rule; /* List of all rules */
- int nstate; /* Number of states */
- int nrule; /* Number of rules */
- int nsymbol; /* Number of terminal and nonterminal symbols */
- int nterminal; /* Number of terminal symbols */
- struct symbol **symbols; /* Sorted array of pointers to symbols */
- int errorcnt; /* Number of errors */
- struct symbol *errsym; /* The error symbol */
- struct symbol *wildcard; /* Token that matches anything */
- char *name; /* Name of the generated parser */
- char *arg; /* Declaration of the 3th argument to parser */
- char *tokentype; /* Type of terminal symbols in the parser stack */
- char *vartype; /* The default type of non-terminal symbols */
- char *start; /* Name of the start symbol for the grammar */
- char *stacksize; /* Size of the parser stack */
- char *include; /* Code to put at the start of the C file */
- int includeln; /* Line number for start of include code */
- char *error; /* Code to execute when an error is seen */
- int errorln; /* Line number for start of error code */
- char *overflow; /* Code to execute on a stack overflow */
- int overflowln; /* Line number for start of overflow code */
- char *failure; /* Code to execute on parser failure */
- int failureln; /* Line number for start of failure code */
- char *accept; /* Code to execute when the parser excepts */
- int acceptln; /* Line number for the start of accept code */
- char *extracode; /* Code appended to the generated file */
- int extracodeln; /* Line number for the start of the extra code */
- char *tokendest; /* Code to execute to destroy token data */
- int tokendestln; /* Line number for token destroyer code */
- char *vardest; /* Code for the default non-terminal destructor */
- int vardestln; /* Line number for default non-term destructor code*/
- char *filename; /* Name of the input file */
- char *outname; /* Name of the current output file */
- char *tokenprefix; /* A prefix added to token names in the .h file */
- int nconflict; /* Number of parsing conflicts */
- int tablesize; /* Size of the parse tables */
- int basisflag; /* Print only basis configurations */
- int has_fallback; /* True if any %fallback is seen in the grammer */
- char *argv0; /* Name of the program */
-};
-
-#define MemoryCheck(X) if((X)==0){ \
- extern void memory_error(); \
- memory_error(); \
-}
-
-/**************** From the file "table.h" *********************************/
-/*
-** All code in this file has been automatically generated
-** from a specification in the file
-** "table.q"
-** by the associative array code building program "aagen".
-** Do not edit this file! Instead, edit the specification
-** file, then rerun aagen.
-*/
-/*
-** Code for processing tables in the LEMON parser generator.
-*/
-
-/* Routines for handling a strings */
-
-char *Strsafe();
-
-void Strsafe_init(/* void */);
-int Strsafe_insert(/* char * */);
-char *Strsafe_find(/* char * */);
-
-/* Routines for handling symbols of the grammar */
-
-struct symbol *Symbol_new();
-int Symbolcmpp(/* struct symbol **, struct symbol ** */);
-void Symbol_init(/* void */);
-int Symbol_insert(/* struct symbol *, char * */);
-struct symbol *Symbol_find(/* char * */);
-struct symbol *Symbol_Nth(/* int */);
-int Symbol_count(/* */);
-struct symbol **Symbol_arrayof(/* */);
-
-/* Routines to manage the state table */
-
-int Configcmp(/* struct config *, struct config * */);
-struct state *State_new();
-void State_init(/* void */);
-int State_insert(/* struct state *, struct config * */);
-struct state *State_find(/* struct config * */);
-struct state **State_arrayof(/* */);
-
-/* Routines used for efficiency in Configlist_add */
-
-void Configtable_init(/* void */);
-int Configtable_insert(/* struct config * */);
-struct config *Configtable_find(/* struct config * */);
-void Configtable_clear(/* int(*)(struct config *) */);
-/****************** From the file "action.c" *******************************/
-/*
-** Routines processing parser actions in the LEMON parser generator.
-*/
-
-/* Allocate a new parser action */
-static struct action *Action_new(void){
- static struct action *freelist = 0;
- struct action *new;
-
- if( freelist==0 ){
- int i;
- int amt = 100;
- freelist = (struct action *)calloc(amt, sizeof(struct action));
- if( freelist==0 ){
- fprintf(stderr,"Unable to allocate memory for a new parser action.");
- exit(1);
- }
- for(i=0; inext;
- return new;
-}
-
-/* Compare two actions for sorting purposes. Return negative, zero, or
-** positive if the first action is less than, equal to, or greater than
-** the first
-*/
-static int actioncmp(
- struct action *ap1,
- struct action *ap2
-){
- int rc;
- rc = ap1->sp->index - ap2->sp->index;
- if( rc==0 ){
- rc = (int)ap1->type - (int)ap2->type;
- }
- if( rc==0 && ap1->type==REDUCE ){
- rc = ap1->x.rp->index - ap2->x.rp->index;
- }
- return rc;
-}
-
-/* Sort parser actions */
-static struct action *Action_sort(
- struct action *ap
-){
- ap = (struct action *)msort((char *)ap,(char **)&ap->next,
- (int(*)(const char*,const char*))actioncmp);
- return ap;
-}
-
-void Action_add(app,type,sp,arg)
-struct action **app;
-enum e_action type;
-struct symbol *sp;
-char *arg;
-{
- struct action *new;
- new = Action_new();
- new->next = *app;
- *app = new;
- new->type = type;
- new->sp = sp;
- if( type==SHIFT ){
- new->x.stp = (struct state *)arg;
- }else{
- new->x.rp = (struct rule *)arg;
- }
-}
-/********************** New code to implement the "acttab" module ***********/
-/*
-** This module implements routines use to construct the yy_action[] table.
-*/
-
-/*
-** The state of the yy_action table under construction is an instance of
-** the following structure
-*/
-typedef struct acttab acttab;
-struct acttab {
- int nAction; /* Number of used slots in aAction[] */
- int nActionAlloc; /* Slots allocated for aAction[] */
- struct {
- int lookahead; /* Value of the lookahead token */
- int action; /* Action to take on the given lookahead */
- } *aAction, /* The yy_action[] table under construction */
- *aLookahead; /* A single new transaction set */
- int mnLookahead; /* Minimum aLookahead[].lookahead */
- int mnAction; /* Action associated with mnLookahead */
- int mxLookahead; /* Maximum aLookahead[].lookahead */
- int nLookahead; /* Used slots in aLookahead[] */
- int nLookaheadAlloc; /* Slots allocated in aLookahead[] */
-};
-
-/* Return the number of entries in the yy_action table */
-#define acttab_size(X) ((X)->nAction)
-
-/* The value for the N-th entry in yy_action */
-#define acttab_yyaction(X,N) ((X)->aAction[N].action)
-
-/* The value for the N-th entry in yy_lookahead */
-#define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead)
-
-/* Free all memory associated with the given acttab */
-void acttab_free(acttab *p){
- free( p->aAction );
- free( p->aLookahead );
- free( p );
-}
-
-/* Allocate a new acttab structure */
-acttab *acttab_alloc(void){
- acttab *p = calloc( 1, sizeof(*p) );
- if( p==0 ){
- fprintf(stderr,"Unable to allocate memory for a new acttab.");
- exit(1);
- }
- memset(p, 0, sizeof(*p));
- return p;
-}
-
-/* Add a new action to the current transaction set
-*/
-void acttab_action(acttab *p, int lookahead, int action){
- if( p->nLookahead>=p->nLookaheadAlloc ){
- p->nLookaheadAlloc += 25;
- p->aLookahead = realloc( p->aLookahead,
- sizeof(p->aLookahead[0])*p->nLookaheadAlloc );
- if( p->aLookahead==0 ){
- fprintf(stderr,"malloc failed\n");
- exit(1);
- }
- }
- if( p->nLookahead==0 ){
- p->mxLookahead = lookahead;
- p->mnLookahead = lookahead;
- p->mnAction = action;
- }else{
- if( p->mxLookaheadmxLookahead = lookahead;
- if( p->mnLookahead>lookahead ){
- p->mnLookahead = lookahead;
- p->mnAction = action;
- }
- }
- p->aLookahead[p->nLookahead].lookahead = lookahead;
- p->aLookahead[p->nLookahead].action = action;
- p->nLookahead++;
-}
-
-/*
-** Add the transaction set built up with prior calls to acttab_action()
-** into the current action table. Then reset the transaction set back
-** to an empty set in preparation for a new round of acttab_action() calls.
-**
-** Return the offset into the action table of the new transaction.
-*/
-int acttab_insert(acttab *p){
- int i, j, k, n;
- assert( p->nLookahead>0 );
-
- /* Make sure we have enough space to hold the expanded action table
- ** in the worst case. The worst case occurs if the transaction set
- ** must be appended to the current action table
- */
- n = p->mxLookahead + 1;
- if( p->nAction + n >= p->nActionAlloc ){
- int oldAlloc = p->nActionAlloc;
- p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20;
- p->aAction = realloc( p->aAction,
- sizeof(p->aAction[0])*p->nActionAlloc);
- if( p->aAction==0 ){
- fprintf(stderr,"malloc failed\n");
- exit(1);
- }
- for(i=oldAlloc; inActionAlloc; i++){
- p->aAction[i].lookahead = -1;
- p->aAction[i].action = -1;
- }
- }
-
- /* Scan the existing action table looking for an offset where we can
- ** insert the current transaction set. Fall out of the loop when that
- ** offset is found. In the worst case, we fall out of the loop when
- ** i reaches p->nAction, which means we append the new transaction set.
- **
- ** i is the index in p->aAction[] where p->mnLookahead is inserted.
- */
- for(i=0; inAction+p->mnLookahead; i++){
- if( p->aAction[i].lookahead<0 ){
- for(j=0; jnLookahead; j++){
- k = p->aLookahead[j].lookahead - p->mnLookahead + i;
- if( k<0 ) break;
- if( p->aAction[k].lookahead>=0 ) break;
- }
- if( jnLookahead ) continue;
- for(j=0; jnAction; j++){
- if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break;
- }
- if( j==p->nAction ){
- break; /* Fits in empty slots */
- }
- }else if( p->aAction[i].lookahead==p->mnLookahead ){
- if( p->aAction[i].action!=p->mnAction ) continue;
- for(j=0; jnLookahead; j++){
- k = p->aLookahead[j].lookahead - p->mnLookahead + i;
- if( k<0 || k>=p->nAction ) break;
- if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break;
- if( p->aLookahead[j].action!=p->aAction[k].action ) break;
- }
- if( jnLookahead ) continue;
- n = 0;
- for(j=0; jnAction; j++){
- if( p->aAction[j].lookahead<0 ) continue;
- if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++;
- }
- if( n==p->nLookahead ){
- break; /* Same as a prior transaction set */
- }
- }
- }
- /* Insert transaction set at index i. */
- for(j=0; jnLookahead; j++){
- k = p->aLookahead[j].lookahead - p->mnLookahead + i;
- p->aAction[k] = p->aLookahead[j];
- if( k>=p->nAction ) p->nAction = k+1;
- }
- p->nLookahead = 0;
-
- /* Return the offset that is added to the lookahead in order to get the
- ** index into yy_action of the action */
- return i - p->mnLookahead;
-}
-
-/********************** From the file "build.c" *****************************/
-/*
-** Routines to construction the finite state machine for the LEMON
-** parser generator.
-*/
-
-/* Find a precedence symbol of every rule in the grammar.
-**
-** Those rules which have a precedence symbol coded in the input
-** grammar using the "[symbol]" construct will already have the
-** rp->precsym field filled. Other rules take as their precedence
-** symbol the first RHS symbol with a defined precedence. If there
-** are not RHS symbols with a defined precedence, the precedence
-** symbol field is left blank.
-*/
-void FindRulePrecedences(xp)
-struct lemon *xp;
-{
- struct rule *rp;
- for(rp=xp->rule; rp; rp=rp->next){
- if( rp->precsym==0 ){
- int i, j;
- for(i=0; inrhs && rp->precsym==0; i++){
- struct symbol *sp = rp->rhs[i];
- if( sp->type==MULTITERMINAL ){
- for(j=0; jnsubsym; j++){
- if( sp->subsym[j]->prec>=0 ){
- rp->precsym = sp->subsym[j];
- break;
- }
- }
- }else if( sp->prec>=0 ){
- rp->precsym = rp->rhs[i];
- }
- }
- }
- }
- return;
-}
-
-/* Find all nonterminals which will generate the empty string.
-** Then go back and compute the first sets of every nonterminal.
-** The first set is the set of all terminal symbols which can begin
-** a string generated by that nonterminal.
-*/
-void FindFirstSets(lemp)
-struct lemon *lemp;
-{
- int i, j;
- struct rule *rp;
- int progress;
-
- for(i=0; insymbol; i++){
- lemp->symbols[i]->lambda = LEMON_FALSE;
- }
- for(i=lemp->nterminal; insymbol; i++){
- lemp->symbols[i]->firstset = SetNew();
- }
-
- /* First compute all lambdas */
- do{
- progress = 0;
- for(rp=lemp->rule; rp; rp=rp->next){
- if( rp->lhs->lambda ) continue;
- for(i=0; inrhs; i++){
- struct symbol *sp = rp->rhs[i];
- if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break;
- }
- if( i==rp->nrhs ){
- rp->lhs->lambda = LEMON_TRUE;
- progress = 1;
- }
- }
- }while( progress );
-
- /* Now compute all first sets */
- do{
- struct symbol *s1, *s2;
- progress = 0;
- for(rp=lemp->rule; rp; rp=rp->next){
- s1 = rp->lhs;
- for(i=0; inrhs; i++){
- s2 = rp->rhs[i];
- if( s2->type==TERMINAL ){
- progress += SetAdd(s1->firstset,s2->index);
- break;
- }else if( s2->type==MULTITERMINAL ){
- for(j=0; jnsubsym; j++){
- progress += SetAdd(s1->firstset,s2->subsym[j]->index);
- }
- break;
- }else if( s1==s2 ){
- if( s1->lambda==LEMON_FALSE ) break;
- }else{
- progress += SetUnion(s1->firstset,s2->firstset);
- if( s2->lambda==LEMON_FALSE ) break;
- }
- }
- }
- }while( progress );
- return;
-}
-
-/* Compute all LR(0) states for the grammar. Links
-** are added to between some states so that the LR(1) follow sets
-** can be computed later.
-*/
-PRIVATE struct state *getstate(/* struct lemon * */); /* forward reference */
-void FindStates(lemp)
-struct lemon *lemp;
-{
- struct symbol *sp;
- struct rule *rp;
-
- Configlist_init();
-
- /* Find the start symbol */
- if( lemp->start ){
- sp = Symbol_find(lemp->start);
- if( sp==0 ){
- ErrorMsg(lemp->filename,0,
-"The specified start symbol \"%s\" is not \
-in a nonterminal of the grammar. \"%s\" will be used as the start \
-symbol instead.",lemp->start,lemp->rule->lhs->name);
- lemp->errorcnt++;
- sp = lemp->rule->lhs;
- }
- }else{
- sp = lemp->rule->lhs;
- }
-
- /* Make sure the start symbol doesn't occur on the right-hand side of
- ** any rule. Report an error if it does. (YACC would generate a new
- ** start symbol in this case.) */
- for(rp=lemp->rule; rp; rp=rp->next){
- int i;
- for(i=0; inrhs; i++){
- if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */
- ErrorMsg(lemp->filename,0,
-"The start symbol \"%s\" occurs on the \
-right-hand side of a rule. This will result in a parser which \
-does not work properly.",sp->name);
- lemp->errorcnt++;
- }
- }
- }
-
- /* The basis configuration set for the first state
- ** is all rules which have the start symbol as their
- ** left-hand side */
- for(rp=sp->rule; rp; rp=rp->nextlhs){
- struct config *newcfp;
- rp->lhsStart = 1;
- newcfp = Configlist_addbasis(rp,0);
- SetAdd(newcfp->fws,0);
- }
-
- /* Compute the first state. All other states will be
- ** computed automatically during the computation of the first one.
- ** The returned pointer to the first state is not used. */
- (void)getstate(lemp);
- return;
-}
-
-/* Return a pointer to a state which is described by the configuration
-** list which has been built from calls to Configlist_add.
-*/
-PRIVATE void buildshifts(/* struct lemon *, struct state * */); /* Forwd ref */
-PRIVATE struct state *getstate(lemp)
-struct lemon *lemp;
-{
- struct config *cfp, *bp;
- struct state *stp;
-
- /* Extract the sorted basis of the new state. The basis was constructed
- ** by prior calls to "Configlist_addbasis()". */
- Configlist_sortbasis();
- bp = Configlist_basis();
-
- /* Get a state with the same basis */
- stp = State_find(bp);
- if( stp ){
- /* A state with the same basis already exists! Copy all the follow-set
- ** propagation links from the state under construction into the
- ** preexisting state, then return a pointer to the preexisting state */
- struct config *x, *y;
- for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){
- Plink_copy(&y->bplp,x->bplp);
- Plink_delete(x->fplp);
- x->fplp = x->bplp = 0;
- }
- cfp = Configlist_return();
- Configlist_eat(cfp);
- }else{
- /* This really is a new state. Construct all the details */
- Configlist_closure(lemp); /* Compute the configuration closure */
- Configlist_sort(); /* Sort the configuration closure */
- cfp = Configlist_return(); /* Get a pointer to the config list */
- stp = State_new(); /* A new state structure */
- MemoryCheck(stp);
- stp->bp = bp; /* Remember the configuration basis */
- stp->cfp = cfp; /* Remember the configuration closure */
- stp->statenum = lemp->nstate++; /* Every state gets a sequence number */
- stp->ap = 0; /* No actions, yet. */
- State_insert(stp,stp->bp); /* Add to the state table */
- buildshifts(lemp,stp); /* Recursively compute successor states */
- }
- return stp;
-}
-
-/*
-** Return true if two symbols are the same.
-*/
-int same_symbol(a,b)
-struct symbol *a;
-struct symbol *b;
-{
- int i;
- if( a==b ) return 1;
- if( a->type!=MULTITERMINAL ) return 0;
- if( b->type!=MULTITERMINAL ) return 0;
- if( a->nsubsym!=b->nsubsym ) return 0;
- for(i=0; insubsym; i++){
- if( a->subsym[i]!=b->subsym[i] ) return 0;
- }
- return 1;
-}
-
-/* Construct all successor states to the given state. A "successor"
-** state is any state which can be reached by a shift action.
-*/
-PRIVATE void buildshifts(lemp,stp)
-struct lemon *lemp;
-struct state *stp; /* The state from which successors are computed */
-{
- struct config *cfp; /* For looping thru the config closure of "stp" */
- struct config *bcfp; /* For the inner loop on config closure of "stp" */
- struct config *new; /* */
- struct symbol *sp; /* Symbol following the dot in configuration "cfp" */
- struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */
- struct state *newstp; /* A pointer to a successor state */
-
- /* Each configuration becomes complete after it contibutes to a successor
- ** state. Initially, all configurations are incomplete */
- for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE;
-
- /* Loop through all configurations of the state "stp" */
- for(cfp=stp->cfp; cfp; cfp=cfp->next){
- if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */
- if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */
- Configlist_reset(); /* Reset the new config set */
- sp = cfp->rp->rhs[cfp->dot]; /* Symbol after the dot */
-
- /* For every configuration in the state "stp" which has the symbol "sp"
- ** following its dot, add the same configuration to the basis set under
- ** construction but with the dot shifted one symbol to the right. */
- for(bcfp=cfp; bcfp; bcfp=bcfp->next){
- if( bcfp->status==COMPLETE ) continue; /* Already used */
- if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */
- bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */
- if( !same_symbol(bsp,sp) ) continue; /* Must be same as for "cfp" */
- bcfp->status = COMPLETE; /* Mark this config as used */
- new = Configlist_addbasis(bcfp->rp,bcfp->dot+1);
- Plink_add(&new->bplp,bcfp);
- }
-
- /* Get a pointer to the state described by the basis configuration set
- ** constructed in the preceding loop */
- newstp = getstate(lemp);
-
- /* The state "newstp" is reached from the state "stp" by a shift action
- ** on the symbol "sp" */
- if( sp->type==MULTITERMINAL ){
- int i;
- for(i=0; insubsym; i++){
- Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp);
- }
- }else{
- Action_add(&stp->ap,SHIFT,sp,(char *)newstp);
- }
- }
-}
-
-/*
-** Construct the propagation links
-*/
-void FindLinks(lemp)
-struct lemon *lemp;
-{
- int i;
- struct config *cfp, *other;
- struct state *stp;
- struct plink *plp;
-
- /* Housekeeping detail:
- ** Add to every propagate link a pointer back to the state to
- ** which the link is attached. */
- for(i=0; instate; i++){
- stp = lemp->sorted[i];
- for(cfp=stp->cfp; cfp; cfp=cfp->next){
- cfp->stp = stp;
- }
- }
-
- /* Convert all backlinks into forward links. Only the forward
- ** links are used in the follow-set computation. */
- for(i=0; instate; i++){
- stp = lemp->sorted[i];
- for(cfp=stp->cfp; cfp; cfp=cfp->next){
- for(plp=cfp->bplp; plp; plp=plp->next){
- other = plp->cfp;
- Plink_add(&other->fplp,cfp);
- }
- }
- }
-}
-
-/* Compute all followsets.
-**
-** A followset is the set of all symbols which can come immediately
-** after a configuration.
-*/
-void FindFollowSets(lemp)
-struct lemon *lemp;
-{
- int i;
- struct config *cfp;
- struct plink *plp;
- int progress;
- int change;
-
- for(i=0; instate; i++){
- for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){
- cfp->status = INCOMPLETE;
- }
- }
-
- do{
- progress = 0;
- for(i=0; instate; i++){
- for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){
- if( cfp->status==COMPLETE ) continue;
- for(plp=cfp->fplp; plp; plp=plp->next){
- change = SetUnion(plp->cfp->fws,cfp->fws);
- if( change ){
- plp->cfp->status = INCOMPLETE;
- progress = 1;
- }
- }
- cfp->status = COMPLETE;
- }
- }
- }while( progress );
-}
-
-static int resolve_conflict();
-
-/* Compute the reduce actions, and resolve conflicts.
-*/
-void FindActions(lemp)
-struct lemon *lemp;
-{
- int i,j;
- struct config *cfp;
- struct state *stp;
- struct symbol *sp;
- struct rule *rp;
-
- /* Add all of the reduce actions
- ** A reduce action is added for each element of the followset of
- ** a configuration which has its dot at the extreme right.
- */
- for(i=0; instate; i++){ /* Loop over all states */
- stp = lemp->sorted[i];
- for(cfp=stp->cfp; cfp; cfp=cfp->next){ /* Loop over all configurations */
- if( cfp->rp->nrhs==cfp->dot ){ /* Is dot at extreme right? */
- for(j=0; jnterminal; j++){
- if( SetFind(cfp->fws,j) ){
- /* Add a reduce action to the state "stp" which will reduce by the
- ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */
- Action_add(&stp->ap,REDUCE,lemp->symbols[j],(char *)cfp->rp);
- }
- }
- }
- }
- }
-
- /* Add the accepting token */
- if( lemp->start ){
- sp = Symbol_find(lemp->start);
- if( sp==0 ) sp = lemp->rule->lhs;
- }else{
- sp = lemp->rule->lhs;
- }
- /* Add to the first state (which is always the starting state of the
- ** finite state machine) an action to ACCEPT if the lookahead is the
- ** start nonterminal. */
- Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0);
-
- /* Resolve conflicts */
- for(i=0; instate; i++){
- struct action *ap, *nap;
- struct state *stp;
- stp = lemp->sorted[i];
- /* assert( stp->ap ); */
- stp->ap = Action_sort(stp->ap);
- for(ap=stp->ap; ap && ap->next; ap=ap->next){
- for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){
- /* The two actions "ap" and "nap" have the same lookahead.
- ** Figure out which one should be used */
- lemp->nconflict += resolve_conflict(ap,nap,lemp->errsym);
- }
- }
- }
-
- /* Report an error for each rule that can never be reduced. */
- for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE;
- for(i=0; instate; i++){
- struct action *ap;
- for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
- if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE;
- }
- }
- for(rp=lemp->rule; rp; rp=rp->next){
- if( rp->canReduce ) continue;
- ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n");
- lemp->errorcnt++;
- }
-}
-
-/* Resolve a conflict between the two given actions. If the
-** conflict can't be resolve, return non-zero.
-**
-** NO LONGER TRUE:
-** To resolve a conflict, first look to see if either action
-** is on an error rule. In that case, take the action which
-** is not associated with the error rule. If neither or both
-** actions are associated with an error rule, then try to
-** use precedence to resolve the conflict.
-**
-** If either action is a SHIFT, then it must be apx. This
-** function won't work if apx->type==REDUCE and apy->type==SHIFT.
-*/
-static int resolve_conflict(apx,apy,errsym)
-struct action *apx;
-struct action *apy;
-struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
-{
- struct symbol *spx, *spy;
- int errcnt = 0;
- assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */
- if( apx->type==SHIFT && apy->type==SHIFT ){
- apy->type = SSCONFLICT;
- errcnt++;
- }
- if( apx->type==SHIFT && apy->type==REDUCE ){
- spx = apx->sp;
- spy = apy->x.rp->precsym;
- if( spy==0 || spx->prec<0 || spy->prec<0 ){
- /* Not enough precedence information. */
- apy->type = SRCONFLICT;
- errcnt++;
- }else if( spx->prec>spy->prec ){ /* Lower precedence wins */
- apy->type = RD_RESOLVED;
- }else if( spx->precprec ){
- apx->type = SH_RESOLVED;
- }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */
- apy->type = RD_RESOLVED; /* associativity */
- }else if( spx->prec==spy->prec && spx->assoc==LEFT ){ /* to break tie */
- apx->type = SH_RESOLVED;
- }else{
- assert( spx->prec==spy->prec && spx->assoc==NONE );
- apy->type = SRCONFLICT;
- errcnt++;
- }
- }else if( apx->type==REDUCE && apy->type==REDUCE ){
- spx = apx->x.rp->precsym;
- spy = apy->x.rp->precsym;
- if( spx==0 || spy==0 || spx->prec<0 ||
- spy->prec<0 || spx->prec==spy->prec ){
- apy->type = RRCONFLICT;
- errcnt++;
- }else if( spx->prec>spy->prec ){
- apy->type = RD_RESOLVED;
- }else if( spx->precprec ){
- apx->type = RD_RESOLVED;
- }
- }else{
- assert(
- apx->type==SH_RESOLVED ||
- apx->type==RD_RESOLVED ||
- apx->type==SSCONFLICT ||
- apx->type==SRCONFLICT ||
- apx->type==RRCONFLICT ||
- apy->type==SH_RESOLVED ||
- apy->type==RD_RESOLVED ||
- apy->type==SSCONFLICT ||
- apy->type==SRCONFLICT ||
- apy->type==RRCONFLICT
- );
- /* The REDUCE/SHIFT case cannot happen because SHIFTs come before
- ** REDUCEs on the list. If we reach this point it must be because
- ** the parser conflict had already been resolved. */
- }
- return errcnt;
-}
-/********************* From the file "configlist.c" *************************/
-/*
-** Routines to processing a configuration list and building a state
-** in the LEMON parser generator.
-*/
-
-static struct config *freelist = 0; /* List of free configurations */
-static struct config *current = 0; /* Top of list of configurations */
-static struct config **currentend = 0; /* Last on list of configs */
-static struct config *basis = 0; /* Top of list of basis configs */
-static struct config **basisend = 0; /* End of list of basis configs */
-
-/* Return a pointer to a new configuration */
-PRIVATE struct config *newconfig(){
- struct config *new;
- if( freelist==0 ){
- int i;
- int amt = 3;
- freelist = (struct config *)calloc( amt, sizeof(struct config) );
- if( freelist==0 ){
- fprintf(stderr,"Unable to allocate memory for a new configuration.");
- exit(1);
- }
- for(i=0; inext;
- return new;
-}
-
-/* The configuration "old" is no longer used */
-PRIVATE void deleteconfig(old)
-struct config *old;
-{
- old->next = freelist;
- freelist = old;
-}
-
-/* Initialized the configuration list builder */
-void Configlist_init(){
- current = 0;
- currentend = ¤t;
- basis = 0;
- basisend = &basis;
- Configtable_init();
- return;
-}
-
-/* Initialized the configuration list builder */
-void Configlist_reset(){
- current = 0;
- currentend = ¤t;
- basis = 0;
- basisend = &basis;
- Configtable_clear(0);
- return;
-}
-
-/* Add another configuration to the configuration list */
-struct config *Configlist_add(rp,dot)
-struct rule *rp; /* The rule */
-int dot; /* Index into the RHS of the rule where the dot goes */
-{
- struct config *cfp, model;
-
- assert( currentend!=0 );
- model.rp = rp;
- model.dot = dot;
- cfp = Configtable_find(&model);
- if( cfp==0 ){
- cfp = newconfig();
- cfp->rp = rp;
- cfp->dot = dot;
- cfp->fws = SetNew();
- cfp->stp = 0;
- cfp->fplp = cfp->bplp = 0;
- cfp->next = 0;
- cfp->bp = 0;
- *currentend = cfp;
- currentend = &cfp->next;
- Configtable_insert(cfp);
- }
- return cfp;
-}
-
-/* Add a basis configuration to the configuration list */
-struct config *Configlist_addbasis(rp,dot)
-struct rule *rp;
-int dot;
-{
- struct config *cfp, model;
-
- assert( basisend!=0 );
- assert( currentend!=0 );
- model.rp = rp;
- model.dot = dot;
- cfp = Configtable_find(&model);
- if( cfp==0 ){
- cfp = newconfig();
- cfp->rp = rp;
- cfp->dot = dot;
- cfp->fws = SetNew();
- cfp->stp = 0;
- cfp->fplp = cfp->bplp = 0;
- cfp->next = 0;
- cfp->bp = 0;
- *currentend = cfp;
- currentend = &cfp->next;
- *basisend = cfp;
- basisend = &cfp->bp;
- Configtable_insert(cfp);
- }
- return cfp;
-}
-
-/* Compute the closure of the configuration list */
-void Configlist_closure(lemp)
-struct lemon *lemp;
-{
- struct config *cfp, *newcfp;
- struct rule *rp, *newrp;
- struct symbol *sp, *xsp;
- int i, dot;
-
- assert( currentend!=0 );
- for(cfp=current; cfp; cfp=cfp->next){
- rp = cfp->rp;
- dot = cfp->dot;
- if( dot>=rp->nrhs ) continue;
- sp = rp->rhs[dot];
- if( sp->type==NONTERMINAL ){
- if( sp->rule==0 && sp!=lemp->errsym ){
- ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.",
- sp->name);
- lemp->errorcnt++;
- }
- for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){
- newcfp = Configlist_add(newrp,0);
- for(i=dot+1; inrhs; i++){
- xsp = rp->rhs[i];
- if( xsp->type==TERMINAL ){
- SetAdd(newcfp->fws,xsp->index);
- break;
- }else if( xsp->type==MULTITERMINAL ){
- int k;
- for(k=0; knsubsym; k++){
- SetAdd(newcfp->fws, xsp->subsym[k]->index);
- }
- break;
- }else{
- SetUnion(newcfp->fws,xsp->firstset);
- if( xsp->lambda==LEMON_FALSE ) break;
- }
- }
- if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp);
- }
- }
- }
- return;
-}
-
-/* Sort the configuration list */
-void Configlist_sort(){
- current = (struct config *)msort((char *)current,(char **)&(current->next),Configcmp);
- currentend = 0;
- return;
-}
-
-/* Sort the basis configuration list */
-void Configlist_sortbasis(){
- basis = (struct config *)msort((char *)current,(char **)&(current->bp),Configcmp);
- basisend = 0;
- return;
-}
-
-/* Return a pointer to the head of the configuration list and
-** reset the list */
-struct config *Configlist_return(){
- struct config *old;
- old = current;
- current = 0;
- currentend = 0;
- return old;
-}
-
-/* Return a pointer to the head of the configuration list and
-** reset the list */
-struct config *Configlist_basis(){
- struct config *old;
- old = basis;
- basis = 0;
- basisend = 0;
- return old;
-}
-
-/* Free all elements of the given configuration list */
-void Configlist_eat(cfp)
-struct config *cfp;
-{
- struct config *nextcfp;
- for(; cfp; cfp=nextcfp){
- nextcfp = cfp->next;
- assert( cfp->fplp==0 );
- assert( cfp->bplp==0 );
- if( cfp->fws ) SetFree(cfp->fws);
- deleteconfig(cfp);
- }
- return;
-}
-/***************** From the file "error.c" *********************************/
-/*
-** Code for printing error message.
-*/
-
-/* Find a good place to break "msg" so that its length is at least "min"
-** but no more than "max". Make the point as close to max as possible.
-*/
-static int findbreak(msg,min,max)
-char *msg;
-int min;
-int max;
-{
- int i,spot;
- char c;
- for(i=spot=min; i<=max; i++){
- c = msg[i];
- if( c=='\t' ) msg[i] = ' ';
- if( c=='\n' ){ msg[i] = ' '; spot = i; break; }
- if( c==0 ){ spot = i; break; }
- if( c=='-' && i0 ){
- sprintf(prefix,"%.*s:%d: ",PREFIXLIMIT-10,filename,lineno);
- }else{
- sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename);
- }
- prefixsize = strlen(prefix);
- availablewidth = LINEWIDTH - prefixsize;
-
- /* Generate the error message */
- vsprintf(errmsg,format,ap);
- va_end(ap);
- errmsgsize = strlen(errmsg);
- /* Remove trailing '\n's from the error message. */
- while( errmsgsize>0 && errmsg[errmsgsize-1]=='\n' ){
- errmsg[--errmsgsize] = 0;
- }
-
- /* Print the error message */
- base = 0;
- while( errmsg[base]!=0 ){
- end = restart = findbreak(&errmsg[base],0,availablewidth);
- restart += base;
- while( errmsg[restart]==' ' ) restart++;
- fprintf(stdout,"%s%.*s\n",prefix,end,&errmsg[base]);
- base = restart;
- }
-}
-/**************** From the file "main.c" ************************************/
-/*
-** Main program file for the LEMON parser generator.
-*/
-
-/* Report an out-of-memory condition and abort. This function
-** is used mostly by the "MemoryCheck" macro in struct.h
-*/
-void memory_error(){
- fprintf(stderr,"Out of memory. Aborting...\n");
- exit(1);
-}
-
-static int nDefine = 0; /* Number of -D options on the command line */
-static char **azDefine = 0; /* Name of the -D macros */
-
-/* This routine is called with the argument to each -D command-line option.
-** Add the macro defined to the azDefine array.
-*/
-static void handle_D_option(char *z){
- char **paz;
- nDefine++;
- azDefine = realloc(azDefine, sizeof(azDefine[0])*nDefine);
- if( azDefine==0 ){
- fprintf(stderr,"out of memory\n");
- exit(1);
- }
- paz = &azDefine[nDefine-1];
- *paz = malloc( strlen(z)+1 );
- if( *paz==0 ){
- fprintf(stderr,"out of memory\n");
- exit(1);
- }
- strcpy(*paz, z);
- for(z=*paz; *z && *z!='='; z++){}
- *z = 0;
-}
-
-
-/* The main program. Parse the command line and do it... */
-int lemon_main(int argc,char **argv)
-{
- static int version = 0;
- static int rpflag = 0;
- static int basisflag = 0;
- static int compress = 0;
- static int quiet = 0;
- static int statistics = 0;
- static int mhflag = 0;
- static struct s_options options[] = {
- {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."},
- {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."},
- {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."},
- {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."},
- {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file"},
- {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."},
- {OPT_FLAG, "s", (char*)&statistics,
- "Print parser stats to standard output."},
- {OPT_FLAG, "x", (char*)&version, "Print the version number."},
- {OPT_FLAG,0,0,0}
- };
- int i;
- struct lemon lem;
-
- OptInit(argv,options,stderr);
- if( version ){
- printf("Lemon version 1.0\n");
- exit(0);
- }
- if( OptNArgs()!=1 ){
- fprintf(stderr,"Exactly one filename argument is required.\n");
- exit(1);
- }
- memset(&lem, 0, sizeof(lem));
- lem.errorcnt = 0;
-
- /* Initialize the machine */
- Strsafe_init();
- Symbol_init();
- State_init();
- lem.argv0 = argv[0];
- lem.filename = OptArg(0);
- lem.basisflag = basisflag;
- Symbol_new("$");
- lem.errsym = Symbol_new("error");
- lem.errsym->useCnt = 0;
-
- /* Parse the input file */
- Parse(&lem);
- if( lem.errorcnt ) exit(lem.errorcnt);
- if( lem.nrule==0 ){
- fprintf(stderr,"Empty grammar.\n");
- exit(1);
- }
-
- /* Count and index the symbols of the grammar */
- lem.nsymbol = Symbol_count();
- Symbol_new("{default}");
- lem.symbols = Symbol_arrayof();
- for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
- qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*),
- (int(*)())Symbolcmpp);
- for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
- for(i=1; isupper(lem.symbols[i]->name[0]); i++);
- lem.nterminal = i;
-
- /* Generate a reprint of the grammar, if requested on the command line */
- if( rpflag ){
- Reprint(&lem);
- }else{
- /* Initialize the size for all follow and first sets */
- SetSize(lem.nterminal+1);
-
- /* Find the precedence for every production rule (that has one) */
- FindRulePrecedences(&lem);
-
- /* Compute the lambda-nonterminals and the first-sets for every
- ** nonterminal */
- FindFirstSets(&lem);
-
- /* Compute all LR(0) states. Also record follow-set propagation
- ** links so that the follow-set can be computed later */
- lem.nstate = 0;
- FindStates(&lem);
- lem.sorted = State_arrayof();
-
- /* Tie up loose ends on the propagation links */
- FindLinks(&lem);
-
- /* Compute the follow set of every reducible configuration */
- FindFollowSets(&lem);
-
- /* Compute the action tables */
- FindActions(&lem);
-
- /* Compress the action tables */
- if( compress==0 ) CompressTables(&lem);
-
- /* Reorder and renumber the states so that states with fewer choices
- ** occur at the end. */
- ResortStates(&lem);
-
- /* Generate a report of the parser generated. (the "y.output" file) */
- if( !quiet ) ReportOutput(&lem);
-
- /* Generate the source code for the parser */
- ReportTable(&lem, mhflag);
-
- /* Produce a header file for use by the scanner. (This step is
- ** omitted if the "-m" option is used because makeheaders will
- ** generate the file for us.) */
- if( !mhflag ) ReportHeader(&lem);
- }
- if( statistics ){
- printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n",
- lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule);
- printf(" %d states, %d parser table entries, %d conflicts\n",
- lem.nstate, lem.tablesize, lem.nconflict);
- }
- exit(lem.errorcnt + lem.nconflict);
- return (lem.errorcnt + lem.nconflict);
-}
-/******************** From the file "msort.c" *******************************/
-/*
-** A generic merge-sort program.
-**
-** USAGE:
-** Let "ptr" be a pointer to some structure which is at the head of
-** a null-terminated list. Then to sort the list call:
-**
-** ptr = msort(ptr,&(ptr->next),cmpfnc);
-**
-** In the above, "cmpfnc" is a pointer to a function which compares
-** two instances of the structure and returns an integer, as in
-** strcmp. The second argument is a pointer to the pointer to the
-** second element of the linked list. This address is used to compute
-** the offset to the "next" field within the structure. The offset to
-** the "next" field must be constant for all structures in the list.
-**
-** The function returns a new pointer which is the head of the list
-** after sorting.
-**
-** ALGORITHM:
-** Merge-sort.
-*/
-
-/*
-** Return a pointer to the next structure in the linked list.
-*/
-#define NEXT(A) (*(char**)(((unsigned long)A)+offset))
-
-/*
-** Inputs:
-** a: A sorted, null-terminated linked list. (May be null).
-** b: A sorted, null-terminated linked list. (May be null).
-** cmp: A pointer to the comparison function.
-** offset: Offset in the structure to the "next" field.
-**
-** Return Value:
-** A pointer to the head of a sorted list containing the elements
-** of both a and b.
-**
-** Side effects:
-** The "next" pointers for elements in the lists a and b are
-** changed.
-*/
-static char *merge(
- char *a,
- char *b,
- int (*cmp)(const char*,const char*),
- int offset
-){
- char *ptr, *head;
-
- if( a==0 ){
- head = b;
- }else if( b==0 ){
- head = a;
- }else{
- if( (*cmp)(a,b)<0 ){
- ptr = a;
- a = NEXT(a);
- }else{
- ptr = b;
- b = NEXT(b);
- }
- head = ptr;
- while( a && b ){
- if( (*cmp)(a,b)<0 ){
- NEXT(ptr) = a;
- ptr = a;
- a = NEXT(a);
- }else{
- NEXT(ptr) = b;
- ptr = b;
- b = NEXT(b);
- }
- }
- if( a ) NEXT(ptr) = a;
- else NEXT(ptr) = b;
- }
- return head;
-}
-
-/*
-** Inputs:
-** list: Pointer to a singly-linked list of structures.
-** next: Pointer to pointer to the second element of the list.
-** cmp: A comparison function.
-**
-** Return Value:
-** A pointer to the head of a sorted list containing the elements
-** orginally in list.
-**
-** Side effects:
-** The "next" pointers for elements in list are changed.
-*/
-#define LISTSIZE 30
-static char *msort(
- char *list,
- char **next,
- int (*cmp)(const char*,const char*)
-){
- unsigned long offset;
- char *ep;
- char *set[LISTSIZE];
- int i;
- offset = (unsigned long)next - (unsigned long)list;
- for(i=0; i0 ){
- fprintf(err,"Valid command line options for \"%s\" are:\n",*a);
- OptPrint();
- exit(1);
- }
- return 0;
-}
-
-int OptNArgs(){
- int cnt = 0;
- int dashdash = 0;
- int i;
- if( argv!=0 && argv[0]!=0 ){
- for(i=1; argv[i]; i++){
- if( dashdash || !ISOPT(argv[i]) ) cnt++;
- if( strcmp(argv[i],"--")==0 ) dashdash = 1;
- }
- }
- return cnt;
-}
-
-char *OptArg(n)
-int n;
-{
- int i;
- i = argindex(n);
- return i>=0 ? argv[i] : 0;
-}
-
-void OptErr(n)
-int n;
-{
- int i;
- i = argindex(n);
- if( i>=0 ) errline(i,0,errstream);
-}
-
-void OptPrint(){
- int i;
- int max, len;
- max = 0;
- for(i=0; op[i].label; i++){
- len = strlen(op[i].label) + 1;
- switch( op[i].type ){
- case OPT_FLAG:
- case OPT_FFLAG:
- break;
- case OPT_INT:
- case OPT_FINT:
- len += 9; /* length of "" */
- break;
- case OPT_DBL:
- case OPT_FDBL:
- len += 6; /* length of "" */
- break;
- case OPT_STR:
- case OPT_FSTR:
- len += 8; /* length of "" */
- break;
- }
- if( len>max ) max = len;
- }
- for(i=0; op[i].label; i++){
- switch( op[i].type ){
- case OPT_FLAG:
- case OPT_FFLAG:
- fprintf(errstream," -%-*s %s\n",max,op[i].label,op[i].message);
- break;
- case OPT_INT:
- case OPT_FINT:
- fprintf(errstream," %s=%*s %s\n",op[i].label,
- (int)(max-strlen(op[i].label)-9),"",op[i].message);
- break;
- case OPT_DBL:
- case OPT_FDBL:
- fprintf(errstream," %s=%*s %s\n",op[i].label,
- (int)(max-strlen(op[i].label)-6),"",op[i].message);
- break;
- case OPT_STR:
- case OPT_FSTR:
- fprintf(errstream," %s=%*s %s\n",op[i].label,
- (int)(max-strlen(op[i].label)-8),"",op[i].message);
- break;
- }
- }
-}
-/*********************** From the file "parse.c" ****************************/
-/*
-** Input file parser for the LEMON parser generator.
-*/
-
-/* The state of the parser */
-struct pstate {
- char *filename; /* Name of the input file */
- int tokenlineno; /* Linenumber at which current token starts */
- int errorcnt; /* Number of errors so far */
- char *tokenstart; /* Text of current token */
- struct lemon *gp; /* Global state vector */
- enum e_state {
- INITIALIZE,
- WAITING_FOR_DECL_OR_RULE,
- WAITING_FOR_DECL_KEYWORD,
- WAITING_FOR_DECL_ARG,
- WAITING_FOR_PRECEDENCE_SYMBOL,
- WAITING_FOR_ARROW,
- IN_RHS,
- LHS_ALIAS_1,
- LHS_ALIAS_2,
- LHS_ALIAS_3,
- RHS_ALIAS_1,
- RHS_ALIAS_2,
- PRECEDENCE_MARK_1,
- PRECEDENCE_MARK_2,
- RESYNC_AFTER_RULE_ERROR,
- RESYNC_AFTER_DECL_ERROR,
- WAITING_FOR_DESTRUCTOR_SYMBOL,
- WAITING_FOR_DATATYPE_SYMBOL,
- WAITING_FOR_FALLBACK_ID,
- WAITING_FOR_WILDCARD_ID
- } state; /* The state of the parser */
- struct symbol *fallback; /* The fallback token */
- struct symbol *lhs; /* Left-hand side of current rule */
- char *lhsalias; /* Alias for the LHS */
- int nrhs; /* Number of right-hand side symbols seen */
- struct symbol *rhs[MAXRHS]; /* RHS symbols */
- char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */
- struct rule *prevrule; /* Previous rule parsed */
- char *declkeyword; /* Keyword of a declaration */
- char **declargslot; /* Where the declaration argument should be put */
- int *decllnslot; /* Where the declaration linenumber is put */
- enum e_assoc declassoc; /* Assign this association to decl arguments */
- int preccounter; /* Assign this precedence to decl arguments */
- struct rule *firstrule; /* Pointer to first rule in the grammar */
- struct rule *lastrule; /* Pointer to the most recently parsed rule */
-};
-
-/* Parse a single token */
-static void parseonetoken(psp)
-struct pstate *psp;
-{
- char *x;
- x = Strsafe(psp->tokenstart); /* Save the token permanently */
-#if 0
- printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno,
- x,psp->state);
-#endif
- switch( psp->state ){
- case INITIALIZE:
- psp->prevrule = 0;
- psp->preccounter = 0;
- psp->firstrule = psp->lastrule = 0;
- psp->gp->nrule = 0;
- /* Fall thru to next case */
- case WAITING_FOR_DECL_OR_RULE:
- if( x[0]=='%' ){
- psp->state = WAITING_FOR_DECL_KEYWORD;
- }else if( islower(x[0]) ){
- psp->lhs = Symbol_new(x);
- psp->nrhs = 0;
- psp->lhsalias = 0;
- psp->state = WAITING_FOR_ARROW;
- }else if( x[0]=='{' ){
- if( psp->prevrule==0 ){
- ErrorMsg(psp->filename,psp->tokenlineno,
-"There is not prior rule opon which to attach the code \
-fragment which begins on this line.");
- psp->errorcnt++;
- }else if( psp->prevrule->code!=0 ){
- ErrorMsg(psp->filename,psp->tokenlineno,
-"Code fragment beginning on this line is not the first \
-to follow the previous rule.");
- psp->errorcnt++;
- }else{
- psp->prevrule->line = psp->tokenlineno;
- psp->prevrule->code = &x[1];
- }
- }else if( x[0]=='[' ){
- psp->state = PRECEDENCE_MARK_1;
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Token \"%s\" should be either \"%%\" or a nonterminal name.",
- x);
- psp->errorcnt++;
- }
- break;
- case PRECEDENCE_MARK_1:
- if( !isupper(x[0]) ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "The precedence symbol must be a terminal.");
- psp->errorcnt++;
- }else if( psp->prevrule==0 ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "There is no prior rule to assign precedence \"[%s]\".",x);
- psp->errorcnt++;
- }else if( psp->prevrule->precsym!=0 ){
- ErrorMsg(psp->filename,psp->tokenlineno,
-"Precedence mark on this line is not the first \
-to follow the previous rule.");
- psp->errorcnt++;
- }else{
- psp->prevrule->precsym = Symbol_new(x);
- }
- psp->state = PRECEDENCE_MARK_2;
- break;
- case PRECEDENCE_MARK_2:
- if( x[0]!=']' ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Missing \"]\" on precedence mark.");
- psp->errorcnt++;
- }
- psp->state = WAITING_FOR_DECL_OR_RULE;
- break;
- case WAITING_FOR_ARROW:
- if( x[0]==':' && x[1]==':' && x[2]=='=' ){
- psp->state = IN_RHS;
- }else if( x[0]=='(' ){
- psp->state = LHS_ALIAS_1;
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Expected to see a \":\" following the LHS symbol \"%s\".",
- psp->lhs->name);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_RULE_ERROR;
- }
- break;
- case LHS_ALIAS_1:
- if( isalpha(x[0]) ){
- psp->lhsalias = x;
- psp->state = LHS_ALIAS_2;
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "\"%s\" is not a valid alias for the LHS \"%s\"\n",
- x,psp->lhs->name);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_RULE_ERROR;
- }
- break;
- case LHS_ALIAS_2:
- if( x[0]==')' ){
- psp->state = LHS_ALIAS_3;
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_RULE_ERROR;
- }
- break;
- case LHS_ALIAS_3:
- if( x[0]==':' && x[1]==':' && x[2]=='=' ){
- psp->state = IN_RHS;
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Missing \"->\" following: \"%s(%s)\".",
- psp->lhs->name,psp->lhsalias);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_RULE_ERROR;
- }
- break;
- case IN_RHS:
- if( x[0]=='.' ){
- struct rule *rp;
- rp = (struct rule *)calloc( sizeof(struct rule) +
- sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1);
- if( rp==0 ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Can't allocate enough memory for this rule.");
- psp->errorcnt++;
- psp->prevrule = 0;
- }else{
- int i;
- rp->ruleline = psp->tokenlineno;
- rp->rhs = (struct symbol**)&rp[1];
- rp->rhsalias = (char**)&(rp->rhs[psp->nrhs]);
- for(i=0; inrhs; i++){
- rp->rhs[i] = psp->rhs[i];
- rp->rhsalias[i] = psp->alias[i];
- }
- rp->lhs = psp->lhs;
- rp->lhsalias = psp->lhsalias;
- rp->nrhs = psp->nrhs;
- rp->code = 0;
- rp->precsym = 0;
- rp->index = psp->gp->nrule++;
- rp->nextlhs = rp->lhs->rule;
- rp->lhs->rule = rp;
- rp->next = 0;
- if( psp->firstrule==0 ){
- psp->firstrule = psp->lastrule = rp;
- }else{
- psp->lastrule->next = rp;
- psp->lastrule = rp;
- }
- psp->prevrule = rp;
- }
- psp->state = WAITING_FOR_DECL_OR_RULE;
- }else if( isalpha(x[0]) ){
- if( psp->nrhs>=MAXRHS ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Too many symbols on RHS of rule beginning at \"%s\".",
- x);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_RULE_ERROR;
- }else{
- psp->rhs[psp->nrhs] = Symbol_new(x);
- psp->alias[psp->nrhs] = 0;
- psp->nrhs++;
- }
- }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){
- struct symbol *msp = psp->rhs[psp->nrhs-1];
- if( msp->type!=MULTITERMINAL ){
- struct symbol *origsp = msp;
- msp = calloc(1,sizeof(*msp));
- memset(msp, 0, sizeof(*msp));
- msp->type = MULTITERMINAL;
- msp->nsubsym = 1;
- msp->subsym = calloc(1,sizeof(struct symbol*));
- msp->subsym[0] = origsp;
- msp->name = origsp->name;
- psp->rhs[psp->nrhs-1] = msp;
- }
- msp->nsubsym++;
- msp->subsym = realloc(msp->subsym, sizeof(struct symbol*)*msp->nsubsym);
- msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]);
- if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Cannot form a compound containing a non-terminal");
- psp->errorcnt++;
- }
- }else if( x[0]=='(' && psp->nrhs>0 ){
- psp->state = RHS_ALIAS_1;
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Illegal character on RHS of rule: \"%s\".",x);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_RULE_ERROR;
- }
- break;
- case RHS_ALIAS_1:
- if( isalpha(x[0]) ){
- psp->alias[psp->nrhs-1] = x;
- psp->state = RHS_ALIAS_2;
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n",
- x,psp->rhs[psp->nrhs-1]->name);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_RULE_ERROR;
- }
- break;
- case RHS_ALIAS_2:
- if( x[0]==')' ){
- psp->state = IN_RHS;
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_RULE_ERROR;
- }
- break;
- case WAITING_FOR_DECL_KEYWORD:
- if( isalpha(x[0]) ){
- psp->declkeyword = x;
- psp->declargslot = 0;
- psp->decllnslot = 0;
- psp->state = WAITING_FOR_DECL_ARG;
- if( strcmp(x,"name")==0 ){
- psp->declargslot = &(psp->gp->name);
- }else if( strcmp(x,"include")==0 ){
- psp->declargslot = &(psp->gp->include);
- psp->decllnslot = &psp->gp->includeln;
- }else if( strcmp(x,"code")==0 ){
- psp->declargslot = &(psp->gp->extracode);
- psp->decllnslot = &psp->gp->extracodeln;
- }else if( strcmp(x,"token_destructor")==0 ){
- psp->declargslot = &psp->gp->tokendest;
- psp->decllnslot = &psp->gp->tokendestln;
- }else if( strcmp(x,"default_destructor")==0 ){
- psp->declargslot = &psp->gp->vardest;
- psp->decllnslot = &psp->gp->vardestln;
- }else if( strcmp(x,"token_prefix")==0 ){
- psp->declargslot = &psp->gp->tokenprefix;
- }else if( strcmp(x,"syntax_error")==0 ){
- psp->declargslot = &(psp->gp->error);
- psp->decllnslot = &psp->gp->errorln;
- }else if( strcmp(x,"parse_accept")==0 ){
- psp->declargslot = &(psp->gp->accept);
- psp->decllnslot = &psp->gp->acceptln;
- }else if( strcmp(x,"parse_failure")==0 ){
- psp->declargslot = &(psp->gp->failure);
- psp->decllnslot = &psp->gp->failureln;
- }else if( strcmp(x,"stack_overflow")==0 ){
- psp->declargslot = &(psp->gp->overflow);
- psp->decllnslot = &psp->gp->overflowln;
- }else if( strcmp(x,"extra_argument")==0 ){
- psp->declargslot = &(psp->gp->arg);
- }else if( strcmp(x,"token_type")==0 ){
- psp->declargslot = &(psp->gp->tokentype);
- }else if( strcmp(x,"default_type")==0 ){
- psp->declargslot = &(psp->gp->vartype);
- }else if( strcmp(x,"stack_size")==0 ){
- psp->declargslot = &(psp->gp->stacksize);
- }else if( strcmp(x,"start_symbol")==0 ){
- psp->declargslot = &(psp->gp->start);
- }else if( strcmp(x,"left")==0 ){
- psp->preccounter++;
- psp->declassoc = LEFT;
- psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
- }else if( strcmp(x,"right")==0 ){
- psp->preccounter++;
- psp->declassoc = RIGHT;
- psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
- }else if( strcmp(x,"nonassoc")==0 ){
- psp->preccounter++;
- psp->declassoc = NONE;
- psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
- }else if( strcmp(x,"destructor")==0 ){
- psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL;
- }else if( strcmp(x,"type")==0 ){
- psp->state = WAITING_FOR_DATATYPE_SYMBOL;
- }else if( strcmp(x,"fallback")==0 ){
- psp->fallback = 0;
- psp->state = WAITING_FOR_FALLBACK_ID;
- }else if( strcmp(x,"wildcard")==0 ){
- psp->state = WAITING_FOR_WILDCARD_ID;
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Unknown declaration keyword: \"%%%s\".",x);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_DECL_ERROR;
- }
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Illegal declaration keyword: \"%s\".",x);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_DECL_ERROR;
- }
- break;
- case WAITING_FOR_DESTRUCTOR_SYMBOL:
- if( !isalpha(x[0]) ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Symbol name missing after %destructor keyword");
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_DECL_ERROR;
- }else{
- struct symbol *sp = Symbol_new(x);
- psp->declargslot = &sp->destructor;
- psp->decllnslot = &sp->destructorln;
- psp->state = WAITING_FOR_DECL_ARG;
- }
- break;
- case WAITING_FOR_DATATYPE_SYMBOL:
- if( !isalpha(x[0]) ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Symbol name missing after %destructor keyword");
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_DECL_ERROR;
- }else{
- struct symbol *sp = Symbol_new(x);
- psp->declargslot = &sp->datatype;
- psp->decllnslot = 0;
- psp->state = WAITING_FOR_DECL_ARG;
- }
- break;
- case WAITING_FOR_PRECEDENCE_SYMBOL:
- if( x[0]=='.' ){
- psp->state = WAITING_FOR_DECL_OR_RULE;
- }else if( isupper(x[0]) ){
- struct symbol *sp;
- sp = Symbol_new(x);
- if( sp->prec>=0 ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Symbol \"%s\" has already be given a precedence.",x);
- psp->errorcnt++;
- }else{
- sp->prec = psp->preccounter;
- sp->assoc = psp->declassoc;
- }
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Can't assign a precedence to \"%s\".",x);
- psp->errorcnt++;
- }
- break;
- case WAITING_FOR_DECL_ARG:
- if( (x[0]=='{' || x[0]=='\"' || isalnum(x[0])) ){
- if( *(psp->declargslot)!=0 ){
- ErrorMsg(psp->filename,psp->tokenlineno,
- "The argument \"%s\" to declaration \"%%%s\" is not the first.",
- x[0]=='\"' ? &x[1] : x,psp->declkeyword);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_DECL_ERROR;
- }else{
- *(psp->declargslot) = (x[0]=='\"' || x[0]=='{') ? &x[1] : x;
- if( psp->decllnslot ) *psp->decllnslot = psp->tokenlineno;
- psp->state = WAITING_FOR_DECL_OR_RULE;
- }
- }else{
- ErrorMsg(psp->filename,psp->tokenlineno,
- "Illegal argument to %%%s: %s",psp->declkeyword,x);
- psp->errorcnt++;
- psp->state = RESYNC_AFTER_DECL_ERROR;
- }
- break;
- case WAITING_FOR_FALLBACK_ID:
- if( x[0]=='.' ){
- psp->state = WAITING_FOR_DECL_OR_RULE;
- }else if( !isupper(x[0]) ){
- ErrorMsg(psp->filename, psp->tokenlineno,
- "%%fallback argument \"%s\" should be a token", x);
- psp->errorcnt++;
- }else{
- struct symbol *sp = Symbol_new(x);
- if( psp->fallback==0 ){
- psp->fallback = sp;
- }else if( sp->fallback ){
- ErrorMsg(psp->filename, psp->tokenlineno,
- "More than one fallback assigned to token %s", x);
- psp->errorcnt++;
- }else{
- sp->fallback = psp->fallback;
- psp->gp->has_fallback = 1;
- }
- }
- break;
- case WAITING_FOR_WILDCARD_ID:
- if( x[0]=='.' ){
- psp->state = WAITING_FOR_DECL_OR_RULE;
- }else if( !isupper(x[0]) ){
- ErrorMsg(psp->filename, psp->tokenlineno,
- "%%wildcard argument \"%s\" should be a token", x);
- psp->errorcnt++;
- }else{
- struct symbol *sp = Symbol_new(x);
- if( psp->gp->wildcard==0 ){
- psp->gp->wildcard = sp;
- }else{
- ErrorMsg(psp->filename, psp->tokenlineno,
- "Extra wildcard to token: %s", x);
- psp->errorcnt++;
- }
- }
- break;
- case RESYNC_AFTER_RULE_ERROR:
-/* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
-** break; */
- case RESYNC_AFTER_DECL_ERROR:
- if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
- if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD;
- break;
- }
-}
-
-/* Run the proprocessor over the input file text. The global variables
-** azDefine[0] through azDefine[nDefine-1] contains the names of all defined
-** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and
-** comments them out. Text in between is also commented out as appropriate.
-*/
-static void preprocess_input(char *z){
- int i, j, k, n;
- int exclude = 0;
- int start = 0;
- int lineno = 1;
- int start_lineno = 1;
- for(i=0; z[i]; i++){
- if( z[i]=='\n' ) lineno++;
- if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue;
- if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){
- if( exclude ){
- exclude--;
- if( exclude==0 ){
- for(j=start; jfilename;
- ps.errorcnt = 0;
- ps.state = INITIALIZE;
-
- /* Begin by reading the input file */
- fp = fopen(ps.filename,"rb");
- if( fp==0 ){
- ErrorMsg(ps.filename,0,"Can't open this file for reading.");
- gp->errorcnt++;
- return;
- }
- fseek(fp,0,2);
- filesize = ftell(fp);
- rewind(fp);
- filebuf = (char *)malloc( filesize+1 );
- if( filebuf==0 ){
- ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.",
- filesize+1);
- gp->errorcnt++;
- return;
- }
- if( fread(filebuf,1,filesize,fp)!=filesize ){
- ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.",
- filesize);
- free(filebuf);
- gp->errorcnt++;
- return;
- }
- fclose(fp);
- filebuf[filesize] = 0;
-
- /* Make an initial pass through the file to handle %ifdef and %ifndef */
- preprocess_input(filebuf);
-
- /* Now scan the text of the input file */
- lineno = 1;
- for(cp=filebuf; (c= *cp)!=0; ){
- if( c=='\n' ) lineno++; /* Keep track of the line number */
- if( isspace(c) ){ cp++; continue; } /* Skip all white space */
- if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */
- cp+=2;
- while( (c= *cp)!=0 && c!='\n' ) cp++;
- continue;
- }
- if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */
- cp+=2;
- while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){
- if( c=='\n' ) lineno++;
- cp++;
- }
- if( c ) cp++;
- continue;
- }
- ps.tokenstart = cp; /* Mark the beginning of the token */
- ps.tokenlineno = lineno; /* Linenumber on which token begins */
- if( c=='\"' ){ /* String literals */
- cp++;
- while( (c= *cp)!=0 && c!='\"' ){
- if( c=='\n' ) lineno++;
- cp++;
- }
- if( c==0 ){
- ErrorMsg(ps.filename,startline,
-"String starting on this line is not terminated before the end of the file.");
- ps.errorcnt++;
- nextcp = cp;
- }else{
- nextcp = cp+1;
- }
- }else if( c=='{' ){ /* A block of C code */
- int level;
- cp++;
- for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){
- if( c=='\n' ) lineno++;
- else if( c=='{' ) level++;
- else if( c=='}' ) level--;
- else if( c=='/' && cp[1]=='*' ){ /* Skip comments */
- int prevc;
- cp = &cp[2];
- prevc = 0;
- while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){
- if( c=='\n' ) lineno++;
- prevc = c;
- cp++;
- }
- }else if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments too */
- cp = &cp[2];
- while( (c= *cp)!=0 && c!='\n' ) cp++;
- if( c ) lineno++;
- }else if( c=='\'' || c=='\"' ){ /* String a character literals */
- int startchar, prevc;
- startchar = c;
- prevc = 0;
- for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){
- if( c=='\n' ) lineno++;
- if( prevc=='\\' ) prevc = 0;
- else prevc = c;
- }
- }
- }
- if( c==0 ){
- ErrorMsg(ps.filename,ps.tokenlineno,
-"C code starting on this line is not terminated before the end of the file.");
- ps.errorcnt++;
- nextcp = cp;
- }else{
- nextcp = cp+1;
- }
- }else if( isalnum(c) ){ /* Identifiers */
- while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++;
- nextcp = cp;
- }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */
- cp += 3;
- nextcp = cp;
- }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){
- cp += 2;
- while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++;
- nextcp = cp;
- }else{ /* All other (one character) operators */
- cp++;
- nextcp = cp;
- }
- c = *cp;
- *cp = 0; /* Null terminate the token */
- parseonetoken(&ps); /* Parse the token */
- *cp = c; /* Restore the buffer */
- cp = nextcp;
- }
- free(filebuf); /* Release the buffer after parsing */
- gp->rule = ps.firstrule;
- gp->errorcnt = ps.errorcnt;
-}
-/*************************** From the file "plink.c" *********************/
-/*
-** Routines processing configuration follow-set propagation links
-** in the LEMON parser generator.
-*/
-static struct plink *plink_freelist = 0;
-
-/* Allocate a new plink */
-struct plink *Plink_new(){
- struct plink *new;
-
- if( plink_freelist==0 ){
- int i;
- int amt = 100;
- plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) );
- if( plink_freelist==0 ){
- fprintf(stderr,
- "Unable to allocate memory for a new follow-set propagation link.\n");
- exit(1);
- }
- for(i=0; inext;
- return new;
-}
-
-/* Add a plink to a plink list */
-void Plink_add(plpp,cfp)
-struct plink **plpp;
-struct config *cfp;
-{
- struct plink *new;
- new = Plink_new();
- new->next = *plpp;
- *plpp = new;
- new->cfp = cfp;
-}
-
-/* Transfer every plink on the list "from" to the list "to" */
-void Plink_copy(to,from)
-struct plink **to;
-struct plink *from;
-{
- struct plink *nextpl;
- while( from ){
- nextpl = from->next;
- from->next = *to;
- *to = from;
- from = nextpl;
- }
-}
-
-/* Delete every plink on the list */
-void Plink_delete(plp)
-struct plink *plp;
-{
- struct plink *nextpl;
-
- while( plp ){
- nextpl = plp->next;
- plp->next = plink_freelist;
- plink_freelist = plp;
- plp = nextpl;
- }
-}
-/*********************** From the file "report.c" **************************/
-/*
-** Procedures for generating reports and tables in the LEMON parser generator.
-*/
-
-/* Generate a filename with the given suffix. Space to hold the
-** name comes from malloc() and must be freed by the calling
-** function.
-*/
-PRIVATE char *file_makename(lemp,suffix)
-struct lemon *lemp;
-char *suffix;
-{
- char *name;
- char *cp;
-
- name = malloc( strlen(lemp->filename) + strlen(suffix) + 5 );
- if( name==0 ){
- fprintf(stderr,"Can't allocate space for a filename.\n");
- exit(1);
- }
- strcpy(name,lemp->filename);
- cp = strrchr(name,'.');
- if( cp ) *cp = 0;
- strcat(name,suffix);
- return name;
-}
-
-/* Open a file with a name based on the name of the input file,
-** but with a different (specified) suffix, and return a pointer
-** to the stream */
-PRIVATE FILE *file_open(lemp,suffix,mode)
-struct lemon *lemp;
-char *suffix;
-char *mode;
-{
- FILE *fp;
-
- if( lemp->outname ) free(lemp->outname);
- lemp->outname = file_makename(lemp, suffix);
- /* LLVM LOCAL begin */
-#if 0
- fp = fopen(lemp->outname,mode);
-#else
- if(*mode == 'r') return NULL;
- fp = stdout;
-#endif
- /* LLVM LOCAL end */
- if( fp==0 && *mode=='w' ){
- fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname);
- lemp->errorcnt++;
- return 0;
- }
- return fp;
-}
-
-/* Duplicate the input file without comments and without actions
-** on rules */
-void Reprint(lemp)
-struct lemon *lemp;
-{
- struct rule *rp;
- struct symbol *sp;
- int i, j, maxlen, len, ncolumns, skip;
- printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename);
- maxlen = 10;
- for(i=0; insymbol; i++){
- sp = lemp->symbols[i];
- len = strlen(sp->name);
- if( len>maxlen ) maxlen = len;
- }
- ncolumns = 76/(maxlen+5);
- if( ncolumns<1 ) ncolumns = 1;
- skip = (lemp->nsymbol + ncolumns - 1)/ncolumns;
- for(i=0; insymbol; j+=skip){
- sp = lemp->symbols[j];
- assert( sp->index==j );
- printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name);
- }
- printf("\n");
- }
- for(rp=lemp->rule; rp; rp=rp->next){
- printf("%s",rp->lhs->name);
- /* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */
- printf(" ::=");
- for(i=0; inrhs; i++){
- sp = rp->rhs[i];
- printf(" %s", sp->name);
- if( sp->type==MULTITERMINAL ){
- for(j=1; jnsubsym; j++){
- printf("|%s", sp->subsym[j]->name);
- }
- }
- /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */
- }
- printf(".");
- if( rp->precsym ) printf(" [%s]",rp->precsym->name);
- /* if( rp->code ) printf("\n %s",rp->code); */
- printf("\n");
- }
-}
-
-void ConfigPrint(fp,cfp)
-FILE *fp;
-struct config *cfp;
-{
- struct rule *rp;
- struct symbol *sp;
- int i, j;
- rp = cfp->rp;
- fprintf(fp,"%s ::=",rp->lhs->name);
- for(i=0; i<=rp->nrhs; i++){
- if( i==cfp->dot ) fprintf(fp," *");
- if( i==rp->nrhs ) break;
- sp = rp->rhs[i];
- fprintf(fp," %s", sp->name);
- if( sp->type==MULTITERMINAL ){
- for(j=1; jnsubsym; j++){
- fprintf(fp,"|%s",sp->subsym[j]->name);
- }
- }
- }
-}
-
-/* #define TEST */
-#if 0
-/* Print a set */
-PRIVATE void SetPrint(out,set,lemp)
-FILE *out;
-char *set;
-struct lemon *lemp;
-{
- int i;
- char *spacer;
- spacer = "";
- fprintf(out,"%12s[","");
- for(i=0; interminal; i++){
- if( SetFind(set,i) ){
- fprintf(out,"%s%s",spacer,lemp->symbols[i]->name);
- spacer = " ";
- }
- }
- fprintf(out,"]\n");
-}
-
-/* Print a plink chain */
-PRIVATE void PlinkPrint(out,plp,tag)
-FILE *out;
-struct plink *plp;
-char *tag;
-{
- while( plp ){
- fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum);
- ConfigPrint(out,plp->cfp);
- fprintf(out,"\n");
- plp = plp->next;
- }
-}
-#endif
-
-/* Print an action to the given file descriptor. Return FALSE if
-** nothing was actually printed.
-*/
-int PrintAction(struct action *ap, FILE *fp, int indent){
- int result = 1;
- switch( ap->type ){
- case SHIFT:
- fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum);
- break;
- case REDUCE:
- fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index);
- break;
- case ACCEPT:
- fprintf(fp,"%*s accept",indent,ap->sp->name);
- break;
- case ERROR:
- fprintf(fp,"%*s error",indent,ap->sp->name);
- break;
- case SRCONFLICT:
- case RRCONFLICT:
- fprintf(fp,"%*s reduce %-3d ** Parsing conflict **",
- indent,ap->sp->name,ap->x.rp->index);
- break;
- case SSCONFLICT:
- fprintf(fp,"%*s shift %d ** Parsing conflict **",
- indent,ap->sp->name,ap->x.stp->statenum);
- break;
- case SH_RESOLVED:
- case RD_RESOLVED:
- case NOT_USED:
- result = 0;
- break;
- }
- return result;
-}
-
-/* Generate the "y.output" log file */
-void ReportOutput(lemp)
-struct lemon *lemp;
-{
- int i;
- struct state *stp;
- struct config *cfp;
- struct action *ap;
- FILE *fp;
-
- fp = file_open(lemp,".out","wb");
- if( fp==0 ) return;
- for(i=0; instate; i++){
- stp = lemp->sorted[i];
- fprintf(fp,"State %d:\n",stp->statenum);
- if( lemp->basisflag ) cfp=stp->bp;
- else cfp=stp->cfp;
- while( cfp ){
- char buf[20];
- if( cfp->dot==cfp->rp->nrhs ){
- sprintf(buf,"(%d)",cfp->rp->index);
- fprintf(fp," %5s ",buf);
- }else{
- fprintf(fp," ");
- }
- ConfigPrint(fp,cfp);
- fprintf(fp,"\n");
-#if 0
- SetPrint(fp,cfp->fws,lemp);
- PlinkPrint(fp,cfp->fplp,"To ");
- PlinkPrint(fp,cfp->bplp,"From");
-#endif
- if( lemp->basisflag ) cfp=cfp->bp;
- else cfp=cfp->next;
- }
- fprintf(fp,"\n");
- for(ap=stp->ap; ap; ap=ap->next){
- if( PrintAction(ap,fp,30) ) fprintf(fp,"\n");
- }
- fprintf(fp,"\n");
- }
- fprintf(fp, "----------------------------------------------------\n");
- fprintf(fp, "Symbols:\n");
- for(i=0; insymbol; i++){
- int j;
- struct symbol *sp;
-
- sp = lemp->symbols[i];
- fprintf(fp, " %3d: %s", i, sp->name);
- if( sp->type==NONTERMINAL ){
- fprintf(fp, ":");
- if( sp->lambda ){
- fprintf(fp, " ");
- }
- for(j=0; jnterminal; j++){
- if( sp->firstset && SetFind(sp->firstset, j) ){
- fprintf(fp, " %s", lemp->symbols[j]->name);
- }
- }
- }
- fprintf(fp, "\n");
- }
-#if 0
- fclose(fp);
-#endif
- return;
-}
-
-/* Search for the file "name" which is in the same directory as
-** the exacutable */
-PRIVATE char *pathsearch(argv0,name,modemask)
-char *argv0;
-char *name;
-int modemask;
-{
- char *pathlist;
- char *path,*cp;
- char c;
-
-#ifdef __WIN32__
- cp = strrchr(argv0,'\\');
-#else
- cp = strrchr(argv0,'/');
-#endif
- if( cp ){
- c = *cp;
- *cp = 0;
- path = (char *)malloc( strlen(argv0) + strlen(name) + 2 );
- if( path ) sprintf(path,"%s/%s",argv0,name);
- *cp = c;
- }else{
- extern char *getenv();
- pathlist = getenv("PATH");
- if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
- path = (char *)malloc( strlen(pathlist)+strlen(name)+2 );
- if( path!=0 ){
- while( *pathlist ){
- cp = strchr(pathlist,':');
- if( cp==0 ) cp = &pathlist[strlen(pathlist)];
- c = *cp;
- *cp = 0;
- sprintf(path,"%s/%s",pathlist,name);
- *cp = c;
- if( c==0 ) pathlist = "";
- else pathlist = &cp[1];
- if( access(path,modemask)==0 ) break;
- }
- }
- }
- return path;
-}
-
-/* Given an action, compute the integer value for that action
-** which is to be put in the action table of the generated machine.
-** Return negative if no action should be generated.
-*/
-PRIVATE int compute_action(lemp,ap)
-struct lemon *lemp;
-struct action *ap;
-{
- int act;
- switch( ap->type ){
- case SHIFT: act = ap->x.stp->statenum; break;
- case REDUCE: act = ap->x.rp->index + lemp->nstate; break;
- case ERROR: act = lemp->nstate + lemp->nrule; break;
- case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break;
- default: act = -1; break;
- }
- return act;
-}
-
-#define LINESIZE 1000
-/* The next cluster of routines are for reading the template file
-** and writing the results to the generated parser */
-/* The first function transfers data from "in" to "out" until
-** a line is seen which begins with "%%". The line number is
-** tracked.
-**
-** if name!=0, then any word that begin with "Parse" is changed to
-** begin with *name instead.
-*/
-PRIVATE void tplt_xfer(name,in,out,lineno)
-char *name;
-FILE *in;
-FILE *out;
-int *lineno;
-{
- int i, iStart;
- char line[LINESIZE];
- while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){
- (*lineno)++;
- iStart = 0;
- if( name ){
- for(i=0; line[i]; i++){
- if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0
- && (i==0 || !isalpha(line[i-1]))
- ){
- if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]);
- fprintf(out,"%s",name);
- i += 4;
- iStart = i+1;
- }
- }
- }
- fprintf(out,"%s",&line[iStart]);
- }
-}
-
-/* The next function finds the template file and opens it, returning
-** a pointer to the opened file. */
-PRIVATE FILE *tplt_open(lemp)
-struct lemon *lemp;
-{
- static char templatename[] = "lempar.c";
- char buf[1000];
- FILE *in;
- char *tpltname;
- char *cp;
-
- cp = strrchr(lemp->filename,'.');
- if( cp ){
- sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename);
- }else{
- sprintf(buf,"%s.lt",lemp->filename);
- }
- if( access(buf,004)==0 ){
- tpltname = buf;
- }else if( access(templatename,004)==0 ){
- tpltname = templatename;
- }else{
- tpltname = pathsearch(lemp->filename,templatename,0);
- }
- if( tpltname==0 ){
- fprintf(stderr,"Can't find the parser driver template file \"%s\".\n",
- templatename);
- lemp->errorcnt++;
- return 0;
- }
- in = fopen(tpltname,"rb");
- if( in==0 ){
- fprintf(stderr,"Can't open the template file \"%s\".\n",templatename);
- lemp->errorcnt++;
- return 0;
- }
- return in;
-}
-
-/* Print a #line directive line to the output file. */
-PRIVATE void tplt_linedir(out,lineno,filename)
-FILE *out;
-int lineno;
-char *filename;
-{
- filename = mybasename(filename);
- fprintf(out,"#line %d \"",lineno);
- while( *filename ){
- if( *filename == '\\' ) putc('\\',out);
- putc(*filename,out);
- filename++;
- }
- fprintf(out,"\"\n");
-}
-
-/* Print a string to the file and keep the linenumber up to date */
-PRIVATE void tplt_print(out,lemp,str,strln,lineno)
-FILE *out;
-struct lemon *lemp;
-char *str;
-int strln;
-int *lineno;
-{
- if( str==0 ) return;
- tplt_linedir(out,strln,lemp->filename);
- (*lineno)++;
- while( *str ){
- if( *str=='\n' ) (*lineno)++;
- putc(*str,out);
- str++;
- }
- if( str[-1]!='\n' ){
- putc('\n',out);
- (*lineno)++;
- }
- tplt_linedir(out,*lineno+2,lemp->outname);
- (*lineno)+=2;
- return;
-}
-
-/*
-** The following routine emits code for the destructor for the
-** symbol sp
-*/
-void emit_destructor_code(out,sp,lemp,lineno)
-FILE *out;
-struct symbol *sp;
-struct lemon *lemp;
-int *lineno;
-{
- char *cp = 0;
-
- int linecnt = 0;
- if( sp->type==TERMINAL ){
- cp = lemp->tokendest;
- if( cp==0 ) return;
- tplt_linedir(out,lemp->tokendestln,lemp->filename);
- fprintf(out,"{");
- }else if( sp->destructor ){
- cp = sp->destructor;
- tplt_linedir(out,sp->destructorln,lemp->filename);
- fprintf(out,"{");
- }else if( lemp->vardest ){
- cp = lemp->vardest;
- if( cp==0 ) return;
- tplt_linedir(out,lemp->vardestln,lemp->filename);
- fprintf(out,"{");
- }else{
- assert( 0 ); /* Cannot happen */
- }
- for(; *cp; cp++){
- if( *cp=='$' && cp[1]=='$' ){
- fprintf(out,"(yypminor->yy%d)",sp->dtnum);
- cp++;
- continue;
- }
- if( *cp=='\n' ) linecnt++;
- fputc(*cp,out);
- }
- (*lineno) += 3 + linecnt;
- fprintf(out,"}\n");
- tplt_linedir(out,*lineno,lemp->outname);
- return;
-}
-
-/*
-** Return TRUE (non-zero) if the given symbol has a destructor.
-*/
-int has_destructor(sp, lemp)
-struct symbol *sp;
-struct lemon *lemp;
-{
- int ret;
- if( sp->type==TERMINAL ){
- ret = lemp->tokendest!=0;
- }else{
- ret = lemp->vardest!=0 || sp->destructor!=0;
- }
- return ret;
-}
-
-/*
-** Append text to a dynamically allocated string. If zText is 0 then
-** reset the string to be empty again. Always return the complete text
-** of the string (which is overwritten with each call).
-**
-** n bytes of zText are stored. If n==0 then all of zText up to the first
-** \000 terminator is stored. zText can contain up to two instances of
-** %d. The values of p1 and p2 are written into the first and second
-** %d.
-**
-** If n==-1, then the previous character is overwritten.
-*/
-PRIVATE char *append_str(char *zText, int n, int p1, int p2){
- static char *z = 0;
- static int alloced = 0;
- static int used = 0;
- int c;
- char zInt[40];
-
- if( zText==0 ){
- used = 0;
- return z;
- }
- if( n<=0 ){
- if( n<0 ){
- used += n;
- assert( used>=0 );
- }
- n = strlen(zText);
- }
- if( n+sizeof(zInt)*2+used >= alloced ){
- alloced = n + sizeof(zInt)*2 + used + 200;
- z = realloc(z, alloced);
- }
- if( z==0 ) return "";
- while( n-- > 0 ){
- c = *(zText++);
- if( c=='%' && n>0 && zText[0]=='d' ){
- sprintf(zInt, "%d", p1);
- p1 = p2;
- strcpy(&z[used], zInt);
- used += strlen(&z[used]);
- zText++;
- n--;
- }else{
- z[used++] = c;
- }
- }
- z[used] = 0;
- return z;
-}
-
-/*
-** zCode is a string that is the action associated with a rule. Expand
-** the symbols in this string so that the refer to elements of the parser
-** stack.
-*/
-PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
- char *cp, *xp;
- int i;
- char lhsused = 0; /* True if the LHS element has been used */
- char used[MAXRHS]; /* True for each RHS element which is used */
-
- for(i=0; inrhs; i++) used[i] = 0;
- lhsused = 0;
-
- if( rp->code==0 ){
- rp->code = "\n";
- rp->line = rp->ruleline;
- }
-
- append_str(0,0,0,0);
- for(cp=rp->code; *cp; cp++){
- if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){
- char saved;
- for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++);
- saved = *xp;
- *xp = 0;
- if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){
- append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0);
- cp = xp;
- lhsused = 1;
- }else{
- for(i=0; inrhs; i++){
- if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){
- if( cp!=rp->code && cp[-1]=='@' ){
- /* If the argument is of the form @X then substituted
- ** the token number of X, not the value of X */
- append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0);
- }else{
- struct symbol *sp = rp->rhs[i];
- int dtnum;
- if( sp->type==MULTITERMINAL ){
- dtnum = sp->subsym[0]->dtnum;
- }else{
- dtnum = sp->dtnum;
- }
- append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum);
- }
- cp = xp;
- used[i] = 1;
- break;
- }
- }
- }
- *xp = saved;
- }
- append_str(cp, 1, 0, 0);
- } /* End loop */
-
- /* Check to make sure the LHS has been used */
- if( rp->lhsalias && !lhsused ){
- ErrorMsg(lemp->filename,rp->ruleline,
- "Label \"%s\" for \"%s(%s)\" is never used.",
- rp->lhsalias,rp->lhs->name,rp->lhsalias);
- lemp->errorcnt++;
- }
-
- /* Generate destructor code for RHS symbols which are not used in the
- ** reduce code */
- for(i=0; inrhs; i++){
- if( rp->rhsalias[i] && !used[i] ){
- ErrorMsg(lemp->filename,rp->ruleline,
- "Label %s for \"%s(%s)\" is never used.",
- rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]);
- lemp->errorcnt++;
- }else if( rp->rhsalias[i]==0 ){
- if( has_destructor(rp->rhs[i],lemp) ){
- append_str(" yy_destructor(%d,&yymsp[%d].minor);\n", 0,
- rp->rhs[i]->index,i-rp->nrhs+1);
- }else{
- /* No destructor defined for this term */
- }
- }
- }
- if( rp->code ){
- cp = append_str(0,0,0,0);
- rp->code = Strsafe(cp?cp:"");
- }
-}
-
-/*
-** Generate code which executes when the rule "rp" is reduced. Write
-** the code to "out". Make sure lineno stays up-to-date.
-*/
-PRIVATE void emit_code(out,rp,lemp,lineno)
-FILE *out;
-struct rule *rp;
-struct lemon *lemp;
-int *lineno;
-{
- char *cp;
- int linecnt = 0;
-
- /* Generate code to do the reduce action */
- if( rp->code ){
- tplt_linedir(out,rp->line,lemp->filename);
- fprintf(out,"{%s",rp->code);
- for(cp=rp->code; *cp; cp++){
- if( *cp=='\n' ) linecnt++;
- } /* End loop */
- (*lineno) += 3 + linecnt;
- fprintf(out,"}\n");
- tplt_linedir(out,*lineno,lemp->outname);
- } /* End if( rp->code ) */
-
- return;
-}
-
-/*
-** Print the definition of the union used for the parser's data stack.
-** This union contains fields for every possible data type for tokens
-** and nonterminals. In the process of computing and printing this
-** union, also set the ".dtnum" field of every terminal and nonterminal
-** symbol.
-*/
-void print_stack_union(out,lemp,plineno,mhflag)
-FILE *out; /* The output stream */
-struct lemon *lemp; /* The main info structure for this parser */
-int *plineno; /* Pointer to the line number */
-int mhflag; /* True if generating makeheaders output */
-{
- int lineno = *plineno; /* The line number of the output */
- char **types; /* A hash table of datatypes */
- int arraysize; /* Size of the "types" array */
- int maxdtlength; /* Maximum length of any ".datatype" field. */
- char *stddt; /* Standardized name for a datatype */
- int i,j; /* Loop counters */
- int hash; /* For hashing the name of a type */
- char *name; /* Name of the parser */
-
- /* Allocate and initialize types[] and allocate stddt[] */
- arraysize = lemp->nsymbol * 2;
- types = (char**)calloc( arraysize, sizeof(char*) );
- for(i=0; ivartype ){
- maxdtlength = strlen(lemp->vartype);
- }
- for(i=0; insymbol; i++){
- int len;
- struct symbol *sp = lemp->symbols[i];
- if( sp->datatype==0 ) continue;
- len = strlen(sp->datatype);
- if( len>maxdtlength ) maxdtlength = len;
- }
- stddt = (char*)malloc( maxdtlength*2 + 1 );
- if( types==0 || stddt==0 ){
- fprintf(stderr,"Out of memory.\n");
- exit(1);
- }
-
- /* Build a hash table of datatypes. The ".dtnum" field of each symbol
- ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is
- ** used for terminal symbols. If there is no %default_type defined then
- ** 0 is also used as the .dtnum value for nonterminals which do not specify
- ** a datatype using the %type directive.
- */
- for(i=0; insymbol; i++){
- struct symbol *sp = lemp->symbols[i];
- char *cp;
- if( sp==lemp->errsym ){
- sp->dtnum = arraysize+1;
- continue;
- }
- if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){
- sp->dtnum = 0;
- continue;
- }
- cp = sp->datatype;
- if( cp==0 ) cp = lemp->vartype;
- j = 0;
- while( isspace(*cp) ) cp++;
- while( *cp ) stddt[j++] = *cp++;
- while( j>0 && isspace(stddt[j-1]) ) j--;
- stddt[j] = 0;
- hash = 0;
- for(j=0; stddt[j]; j++){
- hash = hash*53 + stddt[j];
- }
- hash = (hash & 0x7fffffff)%arraysize;
- while( types[hash] ){
- if( strcmp(types[hash],stddt)==0 ){
- sp->dtnum = hash + 1;
- break;
- }
- hash++;
- if( hash>=arraysize ) hash = 0;
- }
- if( types[hash]==0 ){
- sp->dtnum = hash + 1;
- types[hash] = (char*)malloc( strlen(stddt)+1 );
- if( types[hash]==0 ){
- fprintf(stderr,"Out of memory.\n");
- exit(1);
- }
- strcpy(types[hash],stddt);
- }
- }
-
- /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */
- name = lemp->name ? lemp->name : "Parse";
- lineno = *plineno;
- if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; }
- fprintf(out,"#define %sTOKENTYPE %s\n",name,
- lemp->tokentype?lemp->tokentype:"void*"); lineno++;
- if( mhflag ){ fprintf(out,"#endif\n"); lineno++; }
- fprintf(out,"typedef union {\n"); lineno++;
- fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++;
- for(i=0; ierrsym->useCnt ){
- fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++;
- }
- free(stddt);
- free(types);
- fprintf(out,"} YYMINORTYPE;\n"); lineno++;
- *plineno = lineno;
-}
-
-/*
-** Return the name of a C datatype able to represent values between
-** lwr and upr, inclusive.
-*/
-static const char *minimum_size_type(int lwr, int upr){
- if( lwr>=0 ){
- if( upr<=255 ){
- return "unsigned char";
- }else if( upr<65535 ){
- return "unsigned short int";
- }else{
- return "unsigned int";
- }
- }else if( lwr>=-127 && upr<=127 ){
- return "signed char";
- }else if( lwr>=-32767 && upr<32767 ){
- return "short";
- }else{
- return "int";
- }
-}
-
-/*
-** Each state contains a set of token transaction and a set of
-** nonterminal transactions. Each of these sets makes an instance
-** of the following structure. An array of these structures is used
-** to order the creation of entries in the yy_action[] table.
-*/
-struct axset {
- struct state *stp; /* A pointer to a state */
- int isTkn; /* True to use tokens. False for non-terminals */
- int nAction; /* Number of actions */
-};
-
-/*
-** Compare to axset structures for sorting purposes
-*/
-static int axset_compare(const void *a, const void *b){
- struct axset *p1 = (struct axset*)a;
- struct axset *p2 = (struct axset*)b;
- if (p1->nAction < p2->nAction) return -1;
- if (p1->nAction > p2->nAction) return 1;
- if (p1->isTkn < p2->isTkn) return -1;
- if (p1->isTkn > p2->isTkn) return 1;
- if (p1->stp->statenum < p2->stp->statenum) return -1;
- if (p1->stp->statenum > p2->stp->statenum) return 1;
- return 0;
-}
-
-/*
-** Write text on "out" that describes the rule "rp".
-*/
-static void writeRuleText(FILE *out, struct rule *rp){
- int j;
- fprintf(out,"%s ::=", rp->lhs->name);
- for(j=0; jnrhs; j++){
- struct symbol *sp = rp->rhs[j];
- fprintf(out," %s", sp->name);
- if( sp->type==MULTITERMINAL ){
- int k;
- for(k=1; knsubsym; k++){
- fprintf(out,"|%s",sp->subsym[k]->name);
- }
- }
- }
-}
-
-
-/* Generate C source code for the parser */
-void ReportTable(lemp, mhflag)
-struct lemon *lemp;
-int mhflag; /* Output in makeheaders format if true */
-{
- FILE *out, *in;
- char line[LINESIZE];
- int lineno;
- struct state *stp;
- struct action *ap;
- struct rule *rp;
- struct acttab *pActtab;
- int i, j, n;
- char *name;
- int mnTknOfst, mxTknOfst;
- int mnNtOfst, mxNtOfst;
- struct axset *ax;
-
- in = tplt_open(lemp);
- if( in==0 ) return;
- out = file_open(lemp,".c","wb");
- if( out==0 ){
- fclose(in);
- return;
- }
- lineno = 1;
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate the include code, if any */
- tplt_print(out,lemp,lemp->include,lemp->includeln,&lineno);
- if( mhflag ){
- char *name = file_makename(lemp, ".h");
- fprintf(out,"#include \"%s\"\n", name); lineno++;
- free(name);
- }
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate #defines for all tokens */
- if( mhflag ){
- char *prefix;
- fprintf(out,"#if INTERFACE\n"); lineno++;
- if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
- else prefix = "";
- for(i=1; interminal; i++){
- fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
- lineno++;
- }
- fprintf(out,"#endif\n"); lineno++;
- }
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate the defines */
- fprintf(out,"#define YYCODETYPE %s\n",
- minimum_size_type(0, lemp->nsymbol+5)); lineno++;
- fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++;
- fprintf(out,"#define YYACTIONTYPE %s\n",
- minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++;
- if( lemp->wildcard ){
- fprintf(out,"#define YYWILDCARD %d\n",
- lemp->wildcard->index); lineno++;
- }
- print_stack_union(out,lemp,&lineno,mhflag);
- fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++;
- if( lemp->stacksize ){
- fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++;
- }else{
- fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++;
- }
- fprintf(out, "#endif\n"); lineno++;
- if( mhflag ){
- fprintf(out,"#if INTERFACE\n"); lineno++;
- }
- name = lemp->name ? lemp->name : "Parse";
- if( lemp->arg && lemp->arg[0] ){
- int i;
- i = strlen(lemp->arg);
- while( i>=1 && isspace(lemp->arg[i-1]) ) i--;
- while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--;
- fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++;
- fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg); lineno++;
- fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n",
- name,lemp->arg,&lemp->arg[i]); lineno++;
- fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n",
- name,&lemp->arg[i],&lemp->arg[i]); lineno++;
- }else{
- fprintf(out,"#define %sARG_SDECL\n",name); lineno++;
- fprintf(out,"#define %sARG_PDECL\n",name); lineno++;
- fprintf(out,"#define %sARG_FETCH\n",name); lineno++;
- fprintf(out,"#define %sARG_STORE\n",name); lineno++;
- }
- if( mhflag ){
- fprintf(out,"#endif\n"); lineno++;
- }
- fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++;
- fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++;
- if( lemp->errsym->useCnt ){
- fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
- fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
- }
- if( lemp->has_fallback ){
- fprintf(out,"#define YYFALLBACK 1\n"); lineno++;
- }
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate the action table and its associates:
- **
- ** yy_action[] A single table containing all actions.
- ** yy_lookahead[] A table containing the lookahead for each entry in
- ** yy_action. Used to detect hash collisions.
- ** yy_shift_ofst[] For each state, the offset into yy_action for
- ** shifting terminals.
- ** yy_reduce_ofst[] For each state, the offset into yy_action for
- ** shifting non-terminals after a reduce.
- ** yy_default[] Default action for each state.
- */
-
- /* Compute the actions on all states and count them up */
- ax = calloc(lemp->nstate*2, sizeof(ax[0]));
- if( ax==0 ){
- fprintf(stderr,"malloc failed\n");
- exit(1);
- }
- for(i=0; instate; i++){
- stp = lemp->sorted[i];
- ax[i*2].stp = stp;
- ax[i*2].isTkn = 1;
- ax[i*2].nAction = stp->nTknAct;
- ax[i*2+1].stp = stp;
- ax[i*2+1].isTkn = 0;
- ax[i*2+1].nAction = stp->nNtAct;
- }
- mxTknOfst = mnTknOfst = 0;
- mxNtOfst = mnNtOfst = 0;
-
- /* Compute the action table. In order to try to keep the size of the
- ** action table to a minimum, the heuristic of placing the largest action
- ** sets first is used.
- */
- qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare);
- pActtab = acttab_alloc();
- for(i=0; instate*2 && ax[i].nAction>0; i++){
- stp = ax[i].stp;
- if( ax[i].isTkn ){
- for(ap=stp->ap; ap; ap=ap->next){
- int action;
- if( ap->sp->index>=lemp->nterminal ) continue;
- action = compute_action(lemp, ap);
- if( action<0 ) continue;
- acttab_action(pActtab, ap->sp->index, action);
- }
- stp->iTknOfst = acttab_insert(pActtab);
- if( stp->iTknOfstiTknOfst;
- if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst;
- }else{
- for(ap=stp->ap; ap; ap=ap->next){
- int action;
- if( ap->sp->indexnterminal ) continue;
- if( ap->sp->index==lemp->nsymbol ) continue;
- action = compute_action(lemp, ap);
- if( action<0 ) continue;
- acttab_action(pActtab, ap->sp->index, action);
- }
- stp->iNtOfst = acttab_insert(pActtab);
- if( stp->iNtOfstiNtOfst;
- if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst;
- }
- }
- free(ax);
-
- /* Output the yy_action table */
- fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++;
- n = acttab_size(pActtab);
- for(i=j=0; instate + lemp->nrule + 2;
- if( j==0 ) fprintf(out," /* %5d */ ", i);
- fprintf(out, " %4d,", action);
- if( j==9 || i==n-1 ){
- fprintf(out, "\n"); lineno++;
- j = 0;
- }else{
- j++;
- }
- }
- fprintf(out, "};\n"); lineno++;
-
- /* Output the yy_lookahead table */
- fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++;
- for(i=j=0; insymbol;
- if( j==0 ) fprintf(out," /* %5d */ ", i);
- fprintf(out, " %4d,", la);
- if( j==9 || i==n-1 ){
- fprintf(out, "\n"); lineno++;
- j = 0;
- }else{
- j++;
- }
- }
- fprintf(out, "};\n"); lineno++;
-
- /* Output the yy_shift_ofst[] table */
- fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
- n = lemp->nstate;
- while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--;
- fprintf(out, "#define YY_SHIFT_MAX %d\n", n-1); lineno++;
- fprintf(out, "static const %s yy_shift_ofst[] = {\n",
- minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
- for(i=j=0; isorted[i];
- ofst = stp->iTknOfst;
- if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1;
- if( j==0 ) fprintf(out," /* %5d */ ", i);
- fprintf(out, " %4d,", ofst);
- if( j==9 || i==n-1 ){
- fprintf(out, "\n"); lineno++;
- j = 0;
- }else{
- j++;
- }
- }
- fprintf(out, "};\n"); lineno++;
-
- /* Output the yy_reduce_ofst[] table */
- fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
- n = lemp->nstate;
- while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--;
- fprintf(out, "#define YY_REDUCE_MAX %d\n", n-1); lineno++;
- fprintf(out, "static const %s yy_reduce_ofst[] = {\n",
- minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
- for(i=j=0; isorted[i];
- ofst = stp->iNtOfst;
- if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1;
- if( j==0 ) fprintf(out," /* %5d */ ", i);
- fprintf(out, " %4d,", ofst);
- if( j==9 || i==n-1 ){
- fprintf(out, "\n"); lineno++;
- j = 0;
- }else{
- j++;
- }
- }
- fprintf(out, "};\n"); lineno++;
-
- /* Output the default action table */
- fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++;
- n = lemp->nstate;
- for(i=j=0; isorted[i];
- if( j==0 ) fprintf(out," /* %5d */ ", i);
- fprintf(out, " %4d,", stp->iDflt);
- if( j==9 || i==n-1 ){
- fprintf(out, "\n"); lineno++;
- j = 0;
- }else{
- j++;
- }
- }
- fprintf(out, "};\n"); lineno++;
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate the table of fallback tokens.
- */
- if( lemp->has_fallback ){
- for(i=0; interminal; i++){
- struct symbol *p = lemp->symbols[i];
- if( p->fallback==0 ){
- fprintf(out, " 0, /* %10s => nothing */\n", p->name);
- }else{
- fprintf(out, " %3d, /* %10s => %s */\n", p->fallback->index,
- p->name, p->fallback->name);
- }
- lineno++;
- }
- }
- tplt_xfer(lemp->name, in, out, &lineno);
-
- /* Generate a table containing the symbolic name of every symbol
- */
- for(i=0; insymbol; i++){
- sprintf(line,"\"%s\",",lemp->symbols[i]->name);
- fprintf(out," %-15s",line);
- if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; }
- }
- if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; }
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate a table containing a text string that describes every
- ** rule in the rule set of the grammer. This information is used
- ** when tracing REDUCE actions.
- */
- for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
- assert( rp->index==i );
- fprintf(out," /* %3d */ \"", i);
- writeRuleText(out, rp);
- fprintf(out,"\",\n"); lineno++;
- }
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate code which executes every time a symbol is popped from
- ** the stack while processing errors or while destroying the parser.
- ** (In other words, generate the %destructor actions)
- */
- if( lemp->tokendest ){
- for(i=0; insymbol; i++){
- struct symbol *sp = lemp->symbols[i];
- if( sp==0 || sp->type!=TERMINAL ) continue;
- fprintf(out," case %d: /* %s */\n",
- sp->index, sp->name); lineno++;
- }
- for(i=0; insymbol && lemp->symbols[i]->type!=TERMINAL; i++);
- if( insymbol ){
- emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
- fprintf(out," break;\n"); lineno++;
- }
- }
- if( lemp->vardest ){
- struct symbol *dflt_sp = 0;
- for(i=0; insymbol; i++){
- struct symbol *sp = lemp->symbols[i];
- if( sp==0 || sp->type==TERMINAL ||
- sp->index<=0 || sp->destructor!=0 ) continue;
- fprintf(out," case %d: /* %s */\n",
- sp->index, sp->name); lineno++;
- dflt_sp = sp;
- }
- if( dflt_sp!=0 ){
- emit_destructor_code(out,dflt_sp,lemp,&lineno);
- fprintf(out," break;\n"); lineno++;
- }
- }
- for(i=0; insymbol; i++){
- struct symbol *sp = lemp->symbols[i];
- if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
- fprintf(out," case %d: /* %s */\n",
- sp->index, sp->name); lineno++;
-
- /* Combine duplicate destructors into a single case */
- for(j=i+1; jnsymbol; j++){
- struct symbol *sp2 = lemp->symbols[j];
- if( sp2 && sp2->type!=TERMINAL && sp2->destructor
- && sp2->dtnum==sp->dtnum
- && strcmp(sp->destructor,sp2->destructor)==0 ){
- fprintf(out," case %d: /* %s */\n",
- sp2->index, sp2->name); lineno++;
- sp2->destructor = 0;
- }
- }
-
- emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
- fprintf(out," break;\n"); lineno++;
- }
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate code which executes whenever the parser stack overflows */
- tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate the table of rule information
- **
- ** Note: This code depends on the fact that rules are number
- ** sequentually beginning with 0.
- */
- for(rp=lemp->rule; rp; rp=rp->next){
- fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++;
- }
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate code which execution during each REDUCE action */
- for(rp=lemp->rule; rp; rp=rp->next){
- translate_code(lemp, rp);
- }
- for(rp=lemp->rule; rp; rp=rp->next){
- struct rule *rp2;
- if( rp->code==0 ) continue;
- fprintf(out," case %d: /* ", rp->index);
- writeRuleText(out, rp);
- fprintf(out, " */\n"); lineno++;
- for(rp2=rp->next; rp2; rp2=rp2->next){
- if( rp2->code==rp->code ){
- fprintf(out," case %d: /* ", rp2->index);
- writeRuleText(out, rp2);
- fprintf(out," */\n"); lineno++;
- rp2->code = 0;
- }
- }
- emit_code(out,rp,lemp,&lineno);
- fprintf(out," break;\n"); lineno++;
- }
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate code which executes if a parse fails */
- tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno);
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate code which executes when a syntax error occurs */
- tplt_print(out,lemp,lemp->error,lemp->errorln,&lineno);
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Generate code which executes when the parser accepts its input */
- tplt_print(out,lemp,lemp->accept,lemp->acceptln,&lineno);
- tplt_xfer(lemp->name,in,out,&lineno);
-
- /* Append any addition code the user desires */
- tplt_print(out,lemp,lemp->extracode,lemp->extracodeln,&lineno);
-
- fclose(in);
-#if 0
- fclose(out);
-#endif
- return;
-}
-
-/* Generate a header file for the parser */
-void ReportHeader(lemp)
-struct lemon *lemp;
-{
- FILE *out, *in;
- char *prefix;
- char line[LINESIZE];
- char pattern[LINESIZE];
- int i;
-
- if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
- else prefix = "";
- in = file_open(lemp,".h","rb");
- if( in ){
- for(i=1; interminal && fgets(line,LINESIZE,in); i++){
- sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
- if( strcmp(line,pattern) ) break;
- }
- fclose(in);
- if( i==lemp->nterminal ){
- /* No change in the file. Don't rewrite it. */
- return;
- }
- }
- out = file_open(lemp,".h","wb");
- if( out ){
- for(i=1; interminal; i++){
- fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
- }
-#if 0
- fclose(out);
-#endif
- }
- return;
-}
-
-/* Reduce the size of the action tables, if possible, by making use
-** of defaults.
-**
-** In this version, we take the most frequent REDUCE action and make
-** it the default. Except, there is no default if the wildcard token
-** is a possible look-ahead.
-*/
-void CompressTables(lemp)
-struct lemon *lemp;
-{
- struct state *stp;
- struct action *ap, *ap2;
- struct rule *rp, *rp2, *rbest;
- int nbest, n;
- int i;
- int usesWildcard;
-
- for(i=0; instate; i++){
- stp = lemp->sorted[i];
- nbest = 0;
- rbest = 0;
- usesWildcard = 0;
-
- for(ap=stp->ap; ap; ap=ap->next){
- if( ap->type==SHIFT && ap->sp==lemp->wildcard ){
- usesWildcard = 1;
- }
- if( ap->type!=REDUCE ) continue;
- rp = ap->x.rp;
- if( rp->lhsStart ) continue;
- if( rp==rbest ) continue;
- n = 1;
- for(ap2=ap->next; ap2; ap2=ap2->next){
- if( ap2->type!=REDUCE ) continue;
- rp2 = ap2->x.rp;
- if( rp2==rbest ) continue;
- if( rp2==rp ) n++;
- }
- if( n>nbest ){
- nbest = n;
- rbest = rp;
- }
- }
-
- /* Do not make a default if the number of rules to default
- ** is not at least 1 or if the wildcard token is a possible
- ** lookahead.
- */
- if( nbest<1 || usesWildcard ) continue;
-
-
- /* Combine matching REDUCE actions into a single default */
- for(ap=stp->ap; ap; ap=ap->next){
- if( ap->type==REDUCE && ap->x.rp==rbest ) break;
- }
- assert( ap );
- ap->sp = Symbol_new("{default}");
- for(ap=ap->next; ap; ap=ap->next){
- if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED;
- }
- stp->ap = Action_sort(stp->ap);
- }
-}
-
-
-/*
-** Compare two states for sorting purposes. The smaller state is the
-** one with the most non-terminal actions. If they have the same number
-** of non-terminal actions, then the smaller is the one with the most
-** token actions.
-*/
-static int stateResortCompare(const void *a, const void *b){
- const struct state *pA = *(const struct state**)a;
- const struct state *pB = *(const struct state**)b;
- if (pA->nNtAct < pB->nNtAct) return -1;
- if (pA->nNtAct > pB->nNtAct) return 1;
- if (pA->nTknAct < pB->nTknAct) return -1;
- if (pA->nTknAct > pB->nTknAct) return 1;
- if (pA->statenum < pB->statenum) return -1;
- if (pA->statenum > pB->statenum) return 1;
- return 0;
-}
-
-
-/*
-** Renumber and resort states so that states with fewer choices
-** occur at the end. Except, keep state 0 as the first state.
-*/
-void ResortStates(lemp)
-struct lemon *lemp;
-{
- int i;
- struct state *stp;
- struct action *ap;
-
- for(i=0; instate; i++){
- stp = lemp->sorted[i];
- stp->nTknAct = stp->nNtAct = 0;
- stp->iDflt = lemp->nstate + lemp->nrule;
- stp->iTknOfst = NO_OFFSET;
- stp->iNtOfst = NO_OFFSET;
- for(ap=stp->ap; ap; ap=ap->next){
- if( compute_action(lemp,ap)>=0 ){
- if( ap->sp->indexnterminal ){
- stp->nTknAct++;
- }else if( ap->sp->indexnsymbol ){
- stp->nNtAct++;
- }else{
- stp->iDflt = compute_action(lemp, ap);
- }
- }
- }
- }
- qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]),
- stateResortCompare);
- for(i=0; instate; i++){
- lemp->sorted[i]->statenum = i;
- }
-}
-
-
-/***************** From the file "set.c" ************************************/
-/*
-** Set manipulation routines for the LEMON parser generator.
-*/
-
-static int size = 0;
-
-/* Set the set size */
-void SetSize(n)
-int n;
-{
- size = n+1;
-}
-
-/* Allocate a new set */
-char *SetNew(){
- char *s;
- s = (char*)calloc( size, 1);
- if( s==0 ){
- extern void memory_error();
- memory_error();
- }
- return s;
-}
-
-/* Deallocate a set */
-void SetFree(s)
-char *s;
-{
- free(s);
-}
-
-/* Add a new element to the set. Return TRUE if the element was added
-** and FALSE if it was already there. */
-int SetAdd(s,e)
-char *s;
-int e;
-{
- int rv;
- assert( e>=0 && esize = 1024;
- x1a->count = 0;
- x1a->tbl = (x1node*)malloc(
- (sizeof(x1node) + sizeof(x1node*))*1024 );
- if( x1a->tbl==0 ){
- free(x1a);
- x1a = 0;
- }else{
- int i;
- x1a->ht = (x1node**)&(x1a->tbl[1024]);
- for(i=0; i<1024; i++) x1a->ht[i] = 0;
- }
- }
-}
-/* Insert a new record into the array. Return TRUE if successful.
-** Prior data with the same key is NOT overwritten */
-int Strsafe_insert(data)
-char *data;
-{
- x1node *np;
- int h;
- int ph;
-
- if( x1a==0 ) return 0;
- ph = strhash(data);
- h = ph & (x1a->size-1);
- np = x1a->ht[h];
- while( np ){
- if( strcmp(np->data,data)==0 ){
- /* An existing entry with the same key is found. */
- /* Fail because overwrite is not allows. */
- return 0;
- }
- np = np->next;
- }
- if( x1a->count>=x1a->size ){
- /* Need to make the hash table bigger */
- int i,size;
- struct s_x1 array;
- array.size = size = x1a->size*2;
- array.count = x1a->count;
- array.tbl = (x1node*)malloc(
- (sizeof(x1node) + sizeof(x1node*))*size );
- if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
- array.ht = (x1node**)&(array.tbl[size]);
- for(i=0; icount; i++){
- x1node *oldnp, *newnp;
- oldnp = &(x1a->tbl[i]);
- h = strhash(oldnp->data) & (size-1);
- newnp = &(array.tbl[i]);
- if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
- newnp->next = array.ht[h];
- newnp->data = oldnp->data;
- newnp->from = &(array.ht[h]);
- array.ht[h] = newnp;
- }
- free(x1a->tbl);
- *x1a = array;
- }
- /* Insert the new data */
- h = ph & (x1a->size-1);
- np = &(x1a->tbl[x1a->count++]);
- np->data = data;
- if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next);
- np->next = x1a->ht[h];
- x1a->ht[h] = np;
- np->from = &(x1a->ht[h]);
- return 1;
-}
-
-/* Return a pointer to data assigned to the given key. Return NULL
-** if no such key. */
-char *Strsafe_find(key)
-char *key;
-{
- int h;
- x1node *np;
-
- if( x1a==0 ) return 0;
- h = strhash(key) & (x1a->size-1);
- np = x1a->ht[h];
- while( np ){
- if( strcmp(np->data,key)==0 ) break;
- np = np->next;
- }
- return np ? np->data : 0;
-}
-
-/* Return a pointer to the (terminal or nonterminal) symbol "x".
-** Create a new symbol if this is the first time "x" has been seen.
-*/
-struct symbol *Symbol_new(x)
-char *x;
-{
- struct symbol *sp;
-
- sp = Symbol_find(x);
- if( sp==0 ){
- sp = (struct symbol *)calloc(1, sizeof(struct symbol) );
- MemoryCheck(sp);
- sp->name = Strsafe(x);
- sp->type = isupper(*x) ? TERMINAL : NONTERMINAL;
- sp->rule = 0;
- sp->fallback = 0;
- sp->prec = -1;
- sp->assoc = UNK;
- sp->firstset = 0;
- sp->lambda = LEMON_FALSE;
- sp->destructor = 0;
- sp->datatype = 0;
- sp->useCnt = 0;
- Symbol_insert(sp,sp->name);
- }
- sp->useCnt++;
- return sp;
-}
-
-/* Compare two symbols for working purposes
-**
-** Symbols that begin with upper case letters (terminals or tokens)
-** must sort before symbols that begin with lower case letters
-** (non-terminals). Other than that, the order does not matter.
-**
-** We find experimentally that leaving the symbols in their original
-** order (the order they appeared in the grammar file) gives the
-** smallest parser tables in SQLite.
-*/
-int Symbolcmpp(struct symbol **a, struct symbol **b){
- int indexA = (**a).index;
- int indexB = (**b).index;
- int i1 = indexA + 10000000*((**a).name[0]>'Z');
- int i2 = indexB + 10000000*((**b).name[0]>'Z');
- if (i1 < i2) return -1;
- if (i1 > i2) return 1;
- if (indexA < indexB) return -1;
- if (indexA > indexB) return 1;
- return 0;
-}
-
-/* There is one instance of the following structure for each
-** associative array of type "x2".
-*/
-struct s_x2 {
- int size; /* The number of available slots. */
- /* Must be a power of 2 greater than or */
- /* equal to 1 */
- int count; /* Number of currently slots filled */
- struct s_x2node *tbl; /* The data stored here */
- struct s_x2node **ht; /* Hash table for lookups */
-};
-
-/* There is one instance of this structure for every data element
-** in an associative array of type "x2".
-*/
-typedef struct s_x2node {
- struct symbol *data; /* The data */
- char *key; /* The key */
- struct s_x2node *next; /* Next entry with the same hash */
- struct s_x2node **from; /* Previous link */
-} x2node;
-
-/* There is only one instance of the array, which is the following */
-static struct s_x2 *x2a;
-
-/* Allocate a new associative array */
-void Symbol_init(){
- if( x2a ) return;
- x2a = (struct s_x2*)malloc( sizeof(struct s_x2) );
- if( x2a ){
- x2a->size = 128;
- x2a->count = 0;
- x2a->tbl = (x2node*)malloc(
- (sizeof(x2node) + sizeof(x2node*))*128 );
- if( x2a->tbl==0 ){
- free(x2a);
- x2a = 0;
- }else{
- int i;
- x2a->ht = (x2node**)&(x2a->tbl[128]);
- for(i=0; i<128; i++) x2a->ht[i] = 0;
- }
- }
-}
-/* Insert a new record into the array. Return TRUE if successful.
-** Prior data with the same key is NOT overwritten */
-int Symbol_insert(data,key)
-struct symbol *data;
-char *key;
-{
- x2node *np;
- int h;
- int ph;
-
- if( x2a==0 ) return 0;
- ph = strhash(key);
- h = ph & (x2a->size-1);
- np = x2a->ht[h];
- while( np ){
- if( strcmp(np->key,key)==0 ){
- /* An existing entry with the same key is found. */
- /* Fail because overwrite is not allows. */
- return 0;
- }
- np = np->next;
- }
- if( x2a->count>=x2a->size ){
- /* Need to make the hash table bigger */
- int i,size;
- struct s_x2 array;
- array.size = size = x2a->size*2;
- array.count = x2a->count;
- array.tbl = (x2node*)malloc(
- (sizeof(x2node) + sizeof(x2node*))*size );
- if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
- array.ht = (x2node**)&(array.tbl[size]);
- for(i=0; icount; i++){
- x2node *oldnp, *newnp;
- oldnp = &(x2a->tbl[i]);
- h = strhash(oldnp->key) & (size-1);
- newnp = &(array.tbl[i]);
- if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
- newnp->next = array.ht[h];
- newnp->key = oldnp->key;
- newnp->data = oldnp->data;
- newnp->from = &(array.ht[h]);
- array.ht[h] = newnp;
- }
- free(x2a->tbl);
- *x2a = array;
- }
- /* Insert the new data */
- h = ph & (x2a->size-1);
- np = &(x2a->tbl[x2a->count++]);
- np->key = key;
- np->data = data;
- if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next);
- np->next = x2a->ht[h];
- x2a->ht[h] = np;
- np->from = &(x2a->ht[h]);
- return 1;
-}
-
-/* Return a pointer to data assigned to the given key. Return NULL
-** if no such key. */
-struct symbol *Symbol_find(key)
-char *key;
-{
- int h;
- x2node *np;
-
- if( x2a==0 ) return 0;
- h = strhash(key) & (x2a->size-1);
- np = x2a->ht[h];
- while( np ){
- if( strcmp(np->key,key)==0 ) break;
- np = np->next;
- }
- return np ? np->data : 0;
-}
-
-/* Return the n-th data. Return NULL if n is out of range. */
-struct symbol *Symbol_Nth(n)
-int n;
-{
- struct symbol *data;
- if( x2a && n>0 && n<=x2a->count ){
- data = x2a->tbl[n-1].data;
- }else{
- data = 0;
- }
- return data;
-}
-
-/* Return the size of the array */
-int Symbol_count()
-{
- return x2a ? x2a->count : 0;
-}
-
-/* Return an array of pointers to all data in the table.
-** The array is obtained from malloc. Return NULL if memory allocation
-** problems, or if the array is empty. */
-struct symbol **Symbol_arrayof()
-{
- struct symbol **array;
- int i,size;
- if( x2a==0 ) return 0;
- size = x2a->count;
- array = (struct symbol **)calloc(size, sizeof(struct symbol *));
- if( array ){
- for(i=0; itbl[i].data;
- }
- return array;
-}
-
-/* Compare two configurations */
-int Configcmp(a,b)
-struct config *a;
-struct config *b;
-{
- int x;
- x = a->rp->index - b->rp->index;
- if( x==0 ) x = a->dot - b->dot;
- return x;
-}
-
-/* Compare two states */
-PRIVATE int statecmp(a,b)
-struct config *a;
-struct config *b;
-{
- int rc;
- for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){
- rc = a->rp->index - b->rp->index;
- if( rc==0 ) rc = a->dot - b->dot;
- }
- if( rc==0 ){
- if( a ) rc = 1;
- if( b ) rc = -1;
- }
- return rc;
-}
-
-/* Hash a state */
-PRIVATE int statehash(a)
-struct config *a;
-{
- int h=0;
- while( a ){
- h = h*571 + a->rp->index*37 + a->dot;
- a = a->bp;
- }
- return h;
-}
-
-/* Allocate a new state structure */
-struct state *State_new()
-{
- struct state *new;
- new = (struct state *)calloc(1, sizeof(struct state) );
- MemoryCheck(new);
- return new;
-}
-
-/* There is one instance of the following structure for each
-** associative array of type "x3".
-*/
-struct s_x3 {
- int size; /* The number of available slots. */
- /* Must be a power of 2 greater than or */
- /* equal to 1 */
- int count; /* Number of currently slots filled */
- struct s_x3node *tbl; /* The data stored here */
- struct s_x3node **ht; /* Hash table for lookups */
-};
-
-/* There is one instance of this structure for every data element
-** in an associative array of type "x3".
-*/
-typedef struct s_x3node {
- struct state *data; /* The data */
- struct config *key; /* The key */
- struct s_x3node *next; /* Next entry with the same hash */
- struct s_x3node **from; /* Previous link */
-} x3node;
-
-/* There is only one instance of the array, which is the following */
-static struct s_x3 *x3a;
-
-/* Allocate a new associative array */
-void State_init(){
- if( x3a ) return;
- x3a = (struct s_x3*)malloc( sizeof(struct s_x3) );
- if( x3a ){
- x3a->size = 128;
- x3a->count = 0;
- x3a->tbl = (x3node*)malloc(
- (sizeof(x3node) + sizeof(x3node*))*128 );
- if( x3a->tbl==0 ){
- free(x3a);
- x3a = 0;
- }else{
- int i;
- x3a->ht = (x3node**)&(x3a->tbl[128]);
- for(i=0; i<128; i++) x3a->ht[i] = 0;
- }
- }
-}
-/* Insert a new record into the array. Return TRUE if successful.
-** Prior data with the same key is NOT overwritten */
-int State_insert(data,key)
-struct state *data;
-struct config *key;
-{
- x3node *np;
- int h;
- int ph;
-
- if( x3a==0 ) return 0;
- ph = statehash(key);
- h = ph & (x3a->size-1);
- np = x3a->ht[h];
- while( np ){
- if( statecmp(np->key,key)==0 ){
- /* An existing entry with the same key is found. */
- /* Fail because overwrite is not allows. */
- return 0;
- }
- np = np->next;
- }
- if( x3a->count>=x3a->size ){
- /* Need to make the hash table bigger */
- int i,size;
- struct s_x3 array;
- array.size = size = x3a->size*2;
- array.count = x3a->count;
- array.tbl = (x3node*)malloc(
- (sizeof(x3node) + sizeof(x3node*))*size );
- if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
- array.ht = (x3node**)&(array.tbl[size]);
- for(i=0; icount; i++){
- x3node *oldnp, *newnp;
- oldnp = &(x3a->tbl[i]);
- h = statehash(oldnp->key) & (size-1);
- newnp = &(array.tbl[i]);
- if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
- newnp->next = array.ht[h];
- newnp->key = oldnp->key;
- newnp->data = oldnp->data;
- newnp->from = &(array.ht[h]);
- array.ht[h] = newnp;
- }
- free(x3a->tbl);
- *x3a = array;
- }
- /* Insert the new data */
- h = ph & (x3a->size-1);
- np = &(x3a->tbl[x3a->count++]);
- np->key = key;
- np->data = data;
- if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next);
- np->next = x3a->ht[h];
- x3a->ht[h] = np;
- np->from = &(x3a->ht[h]);
- return 1;
-}
-
-/* Return a pointer to data assigned to the given key. Return NULL
-** if no such key. */
-struct state *State_find(key)
-struct config *key;
-{
- int h;
- x3node *np;
-
- if( x3a==0 ) return 0;
- h = statehash(key) & (x3a->size-1);
- np = x3a->ht[h];
- while( np ){
- if( statecmp(np->key,key)==0 ) break;
- np = np->next;
- }
- return np ? np->data : 0;
-}
-
-/* Return an array of pointers to all data in the table.
-** The array is obtained from malloc. Return NULL if memory allocation
-** problems, or if the array is empty. */
-struct state **State_arrayof()
-{
- struct state **array;
- int i,size;
- if( x3a==0 ) return 0;
- size = x3a->count;
- array = (struct state **)malloc( sizeof(struct state *)*size );
- if( array ){
- for(i=0; itbl[i].data;
- }
- return array;
-}
-
-/* Hash a configuration */
-PRIVATE int confighash(a)
-struct config *a;
-{
- int h=0;
- h = h*571 + a->rp->index*37 + a->dot;
- return h;
-}
-
-/* There is one instance of the following structure for each
-** associative array of type "x4".
-*/
-struct s_x4 {
- int size; /* The number of available slots. */
- /* Must be a power of 2 greater than or */
- /* equal to 1 */
- int count; /* Number of currently slots filled */
- struct s_x4node *tbl; /* The data stored here */
- struct s_x4node **ht; /* Hash table for lookups */
-};
-
-/* There is one instance of this structure for every data element
-** in an associative array of type "x4".
-*/
-typedef struct s_x4node {
- struct config *data; /* The data */
- struct s_x4node *next; /* Next entry with the same hash */
- struct s_x4node **from; /* Previous link */
-} x4node;
-
-/* There is only one instance of the array, which is the following */
-static struct s_x4 *x4a;
-
-/* Allocate a new associative array */
-void Configtable_init(){
- if( x4a ) return;
- x4a = (struct s_x4*)malloc( sizeof(struct s_x4) );
- if( x4a ){
- x4a->size = 64;
- x4a->count = 0;
- x4a->tbl = (x4node*)malloc(
- (sizeof(x4node) + sizeof(x4node*))*64 );
- if( x4a->tbl==0 ){
- free(x4a);
- x4a = 0;
- }else{
- int i;
- x4a->ht = (x4node**)&(x4a->tbl[64]);
- for(i=0; i<64; i++) x4a->ht[i] = 0;
- }
- }
-}
-/* Insert a new record into the array. Return TRUE if successful.
-** Prior data with the same key is NOT overwritten */
-int Configtable_insert(data)
-struct config *data;
-{
- x4node *np;
- int h;
- int ph;
-
- if( x4a==0 ) return 0;
- ph = confighash(data);
- h = ph & (x4a->size-1);
- np = x4a->ht[h];
- while( np ){
- if( Configcmp(np->data,data)==0 ){
- /* An existing entry with the same key is found. */
- /* Fail because overwrite is not allows. */
- return 0;
- }
- np = np->next;
- }
- if( x4a->count>=x4a->size ){
- /* Need to make the hash table bigger */
- int i,size;
- struct s_x4 array;
- array.size = size = x4a->size*2;
- array.count = x4a->count;
- array.tbl = (x4node*)malloc(
- (sizeof(x4node) + sizeof(x4node*))*size );
- if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
- array.ht = (x4node**)&(array.tbl[size]);
- for(i=0; icount; i++){
- x4node *oldnp, *newnp;
- oldnp = &(x4a->tbl[i]);
- h = confighash(oldnp->data) & (size-1);
- newnp = &(array.tbl[i]);
- if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
- newnp->next = array.ht[h];
- newnp->data = oldnp->data;
- newnp->from = &(array.ht[h]);
- array.ht[h] = newnp;
- }
- free(x4a->tbl);
- *x4a = array;
- }
- /* Insert the new data */
- h = ph & (x4a->size-1);
- np = &(x4a->tbl[x4a->count++]);
- np->data = data;
- if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next);
- np->next = x4a->ht[h];
- x4a->ht[h] = np;
- np->from = &(x4a->ht[h]);
- return 1;
-}
-
-/* Return a pointer to data assigned to the given key. Return NULL
-** if no such key. */
-struct config *Configtable_find(key)
-struct config *key;
-{
- int h;
- x4node *np;
-
- if( x4a==0 ) return 0;
- h = confighash(key) & (x4a->size-1);
- np = x4a->ht[h];
- while( np ){
- if( Configcmp(np->data,key)==0 ) break;
- np = np->next;
- }
- return np ? np->data : 0;
-}
-
-/* Remove all data from the table. Pass each data to the function "f"
-** as it is removed. ("f" may be null to avoid this step.) */
-void Configtable_clear(f)
-int(*f)(/* struct config * */);
-{
- int i;
- if( x4a==0 || x4a->count==0 ) return;
- if( f ) for(i=0; icount; i++) (*f)(x4a->tbl[i].data);
- for(i=0; isize; i++) x4a->ht[i] = 0;
- x4a->count = 0;
- return;
-}
-
-/* LLVM LOCAL begin */
-
-#include
-#include
-#include
-/* llvm-test supports only running program once,
- * we need to run it multiple times, because it only accepts
- * one input a time, and has a global state */
-int main(int argc, char **argv)
-{
- int j,i = 0;
- for(j=0;j<20;j++) {
- /* test finishes too fast, run more times to get
- * meaningful timings */
- for(i=1;i
-%%
-/* Next is all token values, in a form suitable for use by makeheaders.
-** This section will be null unless lemon is run with the -m switch.
-*/
-/*
-** These constants (all generated automatically by the parser generator)
-** specify the various kinds of tokens (terminals) that the parser
-** understands.
-**
-** Each symbol here is a terminal symbol in the grammar.
-*/
-%%
-/* Make sure the INTERFACE macro is defined.
-*/
-#ifndef INTERFACE
-# define INTERFACE 1
-#endif
-/* The next thing included is series of defines which control
-** various aspects of the generated parser.
-** YYCODETYPE is the data type used for storing terminal
-** and nonterminal numbers. "unsigned char" is
-** used if there are fewer than 250 terminals
-** and nonterminals. "int" is used otherwise.
-** YYNOCODE is a number of type YYCODETYPE which corresponds
-** to no legal terminal or nonterminal number. This
-** number is used to fill in empty slots of the hash
-** table.
-** YYFALLBACK If defined, this indicates that one or more tokens
-** have fall-back values which should be used if the
-** original value of the token will not parse.
-** YYACTIONTYPE is the data type used for storing terminal
-** and nonterminal numbers. "unsigned char" is
-** used if there are fewer than 250 rules and
-** states combined. "int" is used otherwise.
-** ParseTOKENTYPE is the data type used for minor tokens given
-** directly to the parser from the tokenizer.
-** YYMINORTYPE is the data type used for all minor tokens.
-** This is typically a union of many types, one of
-** which is ParseTOKENTYPE. The entry in the union
-** for base tokens is called "yy0".
-** YYSTACKDEPTH is the maximum depth of the parser's stack. If
-** zero the stack is dynamically sized using realloc()
-** ParseARG_SDECL A static variable declaration for the %extra_argument
-** ParseARG_PDECL A parameter declaration for the %extra_argument
-** ParseARG_STORE Code to store %extra_argument into yypParser
-** ParseARG_FETCH Code to extract %extra_argument from yypParser
-** YYNSTATE the combined number of states.
-** YYNRULE the number of rules in the grammar
-** YYERRORSYMBOL is the code number of the error symbol. If not
-** defined, then do no error processing.
-*/
-%%
-#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
-#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
-#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
-
-/* Next are that tables used to determine what action to take based on the
-** current state and lookahead token. These tables are used to implement
-** functions that take a state number and lookahead value and return an
-** action integer.
-**
-** Suppose the action integer is N. Then the action is determined as
-** follows
-**
-** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
-** token onto the stack and goto state N.
-**
-** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
-**
-** N == YYNSTATE+YYNRULE A syntax error has occurred.
-**
-** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
-**
-** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
-** slots in the yy_action[] table.
-**
-** The action table is constructed as a single large table named yy_action[].
-** Given state S and lookahead X, the action is computed as
-**
-** yy_action[ yy_shift_ofst[S] + X ]
-**
-** If the index value yy_shift_ofst[S]+X is out of range or if the value
-** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
-** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
-** and that yy_default[S] should be used instead.
-**
-** The formula above is for computing the action when the lookahead is
-** a terminal symbol. If the lookahead is a non-terminal (as occurs after
-** a reduce action) then the yy_reduce_ofst[] array is used in place of
-** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
-** YY_SHIFT_USE_DFLT.
-**
-** The following are the tables generated in this section:
-**
-** yy_action[] A single table containing all actions.
-** yy_lookahead[] A table containing the lookahead for each entry in
-** yy_action. Used to detect hash collisions.
-** yy_shift_ofst[] For each state, the offset into yy_action for
-** shifting terminals.
-** yy_reduce_ofst[] For each state, the offset into yy_action for
-** shifting non-terminals after a reduce.
-** yy_default[] Default action for each state.
-*/
-%%
-#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
-
-/* The next table maps tokens into fallback tokens. If a construct
-** like the following:
-**
-** %fallback ID X Y Z.
-**
-** appears in the grammer, then ID becomes a fallback token for X, Y,
-** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
-** but it does not parse, the type of the token is changed to ID and
-** the parse is retried before an error is thrown.
-*/
-#ifdef YYFALLBACK
-static const YYCODETYPE yyFallback[] = {
-%%
-};
-#endif /* YYFALLBACK */
-
-/* The following structure represents a single element of the
-** parser's stack. Information stored includes:
-**
-** + The state number for the parser at this level of the stack.
-**
-** + The value of the token stored at this level of the stack.
-** (In other words, the "major" token.)
-**
-** + The semantic value stored at this level of the stack. This is
-** the information used by the action routines in the grammar.
-** It is sometimes called the "minor" token.
-*/
-struct yyStackEntry {
- int stateno; /* The state-number */
- int major; /* The major token value. This is the code
- ** number for the token at this stack level */
- YYMINORTYPE minor; /* The user-supplied minor token value. This
- ** is the value of the token */
-};
-typedef struct yyStackEntry yyStackEntry;
-
-/* The state of the parser is completely contained in an instance of
-** the following structure */
-struct yyParser {
- int yyidx; /* Index of top element in stack */
- int yyerrcnt; /* Shifts left before out of the error */
- ParseARG_SDECL /* A place to hold %extra_argument */
-#if YYSTACKDEPTH<=0
- int yystksz; /* Current side of the stack */
- yyStackEntry *yystack; /* The parser's stack */
-#else
- yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
-#endif
-};
-typedef struct yyParser yyParser;
-
-#ifndef NDEBUG
-#include
-static FILE *yyTraceFILE = 0;
-static char *yyTracePrompt = 0;
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/*
-** Turn parser tracing on by giving a stream to which to write the trace
-** and a prompt to preface each trace message. Tracing is turned off
-** by making either argument NULL
-**
-** Inputs:
-**
-** - A FILE* to which trace output should be written.
-** If NULL, then tracing is turned off.
-**
- A prefix string written at the beginning of every
-** line of trace output. If NULL, then tracing is
-** turned off.
-**
-**
-** Outputs:
-** None.
-*/
-void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
- yyTraceFILE = TraceFILE;
- yyTracePrompt = zTracePrompt;
- if( yyTraceFILE==0 ) yyTracePrompt = 0;
- else if( yyTracePrompt==0 ) yyTraceFILE = 0;
-}
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/* For tracing shifts, the names of all terminals and nonterminals
-** are required. The following table supplies these names */
-static const char *const yyTokenName[] = {
-%%
-};
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/* For tracing reduce actions, the names of all rules are required.
-*/
-static const char *const yyRuleName[] = {
-%%
-};
-#endif /* NDEBUG */
-
-
-#if YYSTACKDEPTH<=0
-/*
-** Try to increase the size of the parser stack.
-*/
-static void yyGrowStack(yyParser *p){
- int newSize;
- yyStackEntry *pNew;
-
- newSize = p->yystksz*2 + 100;
- pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
- if( pNew ){
- p->yystack = pNew;
- p->yystksz = newSize;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
- yyTracePrompt, p->yystksz);
- }
-#endif
- }
-}
-#endif
-
-/*
-** This function allocates a new parser.
-** The only argument is a pointer to a function which works like
-** malloc.
-**
-** Inputs:
-** A pointer to the function used to allocate memory.
-**
-** Outputs:
-** A pointer to a parser. This pointer is used in subsequent calls
-** to Parse and ParseFree.
-*/
-void *ParseAlloc(void *(*mallocProc)(size_t)){
- yyParser *pParser;
- pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
- if( pParser ){
- pParser->yyidx = -1;
-#if YYSTACKDEPTH<=0
- yyGrowStack(pParser);
-#endif
- }
- return pParser;
-}
-
-/* The following function deletes the value associated with a
-** symbol. The symbol can be either a terminal or nonterminal.
-** "yymajor" is the symbol code, and "yypminor" is a pointer to
-** the value.
-*/
-static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
- switch( yymajor ){
- /* Here is inserted the actions which take place when a
- ** terminal or non-terminal is destroyed. This can happen
- ** when the symbol is popped from the stack during a
- ** reduce or during error processing or when a parser is
- ** being destroyed before it is finished parsing.
- **
- ** Note: during a reduce, the only symbols destroyed are those
- ** which appear on the RHS of the rule, but which are not used
- ** inside the C code.
- */
-%%
- default: break; /* If no destructor action specified: do nothing */
- }
-}
-
-/*
-** Pop the parser's stack once.
-**
-** If there is a destructor routine associated with the token which
-** is popped from the stack, then call it.
-**
-** Return the major token number for the symbol popped.
-*/
-static int yy_pop_parser_stack(yyParser *pParser){
- YYCODETYPE yymajor;
- yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
-
- if( pParser->yyidx<0 ) return 0;
-#ifndef NDEBUG
- if( yyTraceFILE && pParser->yyidx>=0 ){
- fprintf(yyTraceFILE,"%sPopping %s\n",
- yyTracePrompt,
- yyTokenName[yytos->major]);
- }
-#endif
- yymajor = yytos->major;
- yy_destructor( yymajor, &yytos->minor);
- pParser->yyidx--;
- return yymajor;
-}
-
-/*
-** Deallocate and destroy a parser. Destructors are all called for
-** all stack elements before shutting the parser down.
-**
-** Inputs:
-**
-** - A pointer to the parser. This should be a pointer
-** obtained from ParseAlloc.
-**
- A pointer to a function used to reclaim memory obtained
-** from malloc.
-**
-*/
-void ParseFree(
- void *p, /* The parser to be deleted */
- void (*freeProc)(void*) /* Function used to reclaim memory */
-){
- yyParser *pParser = (yyParser*)p;
- if( pParser==0 ) return;
- while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
-#if YYSTACKDEPTH<=0
- free(pParser->yystack);
-#endif
- (*freeProc)((void*)pParser);
-}
-
-/*
-** Find the appropriate action for a parser given the terminal
-** look-ahead token iLookAhead.
-**
-** If the look-ahead token is YYNOCODE, then check to see if the action is
-** independent of the look-ahead. If it is, return the action, otherwise
-** return YY_NO_ACTION.
-*/
-static int yy_find_shift_action(
- yyParser *pParser, /* The parser */
- YYCODETYPE iLookAhead /* The look-ahead token */
-){
- int i;
- int stateno = pParser->yystack[pParser->yyidx].stateno;
-
- if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
- return yy_default[stateno];
- }
- assert( iLookAhead!=YYNOCODE );
- i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
- if( iLookAhead>0 ){
-#ifdef YYFALLBACK
- int iFallback; /* Fallback token */
- if( iLookAhead %s\n",
- yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
- }
-#endif
- return yy_find_shift_action(pParser, iFallback);
- }
-#endif
-#ifdef YYWILDCARD
- {
- int j = i - iLookAhead + YYWILDCARD;
- if( j>=0 && j %s\n",
- yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
- }
-#endif /* NDEBUG */
- return yy_action[j];
- }
- }
-#endif /* YYWILDCARD */
- }
- return yy_default[stateno];
- }else{
- return yy_action[i];
- }
-}
-
-/*
-** Find the appropriate action for a parser given the non-terminal
-** look-ahead token iLookAhead.
-**
-** If the look-ahead token is YYNOCODE, then check to see if the action is
-** independent of the look-ahead. If it is, return the action, otherwise
-** return YY_NO_ACTION.
-*/
-static int yy_find_reduce_action(
- int stateno, /* Current state number */
- YYCODETYPE iLookAhead /* The look-ahead token */
-){
- int i;
- assert( stateno<=YY_REDUCE_MAX );
- i = yy_reduce_ofst[stateno];
- assert( i!=YY_REDUCE_USE_DFLT );
- assert( iLookAhead!=YYNOCODE );
- i += iLookAhead;
- assert( i>=0 && iyyidx--;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will execute if the parser
- ** stack every overflows */
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
-}
-
-/*
-** Perform a shift action.
-*/
-static void yy_shift(
- yyParser *yypParser, /* The parser to be shifted */
- int yyNewState, /* The new state to shift in */
- int yyMajor, /* The major token to shift in */
- YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
-){
- yyStackEntry *yytos;
- yypParser->yyidx++;
-#if YYSTACKDEPTH>0
- if( yypParser->yyidx>=YYSTACKDEPTH ){
- yyStackOverflow(yypParser, yypMinor);
- return;
- }
-#else
- if( yypParser->yyidx>=yypParser->yystksz ){
- yyGrowStack(yypParser);
- if( yypParser->yyidx>=yypParser->yystksz ){
- yyStackOverflow(yypParser, yypMinor);
- return;
- }
- }
-#endif
- yytos = &yypParser->yystack[yypParser->yyidx];
- yytos->stateno = yyNewState;
- yytos->major = yyMajor;
- yytos->minor = *yypMinor;
-#ifndef NDEBUG
- if( yyTraceFILE && yypParser->yyidx>0 ){
- int i;
- fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
- fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
- for(i=1; i<=yypParser->yyidx; i++)
- fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
- fprintf(yyTraceFILE,"\n");
- }
-#endif
-}
-
-/* The following table contains information about every rule that
-** is used during the reduce.
-*/
-static const struct {
- YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
- unsigned char nrhs; /* Number of right-hand side symbols in the rule */
-} yyRuleInfo[] = {
-%%
-};
-
-static void yy_accept(yyParser*); /* Forward Declaration */
-
-/*
-** Perform a reduce action and the shift that must immediately
-** follow the reduce.
-*/
-static void yy_reduce(
- yyParser *yypParser, /* The parser */
- int yyruleno /* Number of the rule by which to reduce */
-){
- int yygoto; /* The next state */
- int yyact; /* The next action */
- YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
- yyStackEntry *yymsp; /* The top of the parser's stack */
- int yysize; /* Amount to pop the stack */
- ParseARG_FETCH;
- yymsp = &yypParser->yystack[yypParser->yyidx];
-#ifndef NDEBUG
- if( yyTraceFILE && yyruleno>=0
- && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
- fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
- yyRuleName[yyruleno]);
- }
-#endif /* NDEBUG */
-
- /* Silence complaints from purify about yygotominor being uninitialized
- ** in some cases when it is copied into the stack after the following
- ** switch. yygotominor is uninitialized when a rule reduces that does
- ** not set the value of its left-hand side nonterminal. Leaving the
- ** value of the nonterminal uninitialized is utterly harmless as long
- ** as the value is never used. So really the only thing this code
- ** accomplishes is to quieten purify.
- **
- ** 2007-01-16: The wireshark project (www.wireshark.org) reports that
- ** without this code, their parser segfaults. I'm not sure what there
- ** parser is doing to make this happen. This is the second bug report
- ** from wireshark this week. Clearly they are stressing Lemon in ways
- ** that it has not been previously stressed... (SQLite ticket #2172)
- */
- memset(&yygotominor, 0, sizeof(yygotominor));
-
-
- switch( yyruleno ){
- /* Beginning here are the reduction cases. A typical example
- ** follows:
- ** case 0:
- ** #line
- ** { ... } // User supplied code
- ** #line
- ** break;
- */
-%%
- };
- yygoto = yyRuleInfo[yyruleno].lhs;
- yysize = yyRuleInfo[yyruleno].nrhs;
- yypParser->yyidx -= yysize;
- yyact = yy_find_reduce_action(yymsp[-yysize].stateno,yygoto);
- if( yyact < YYNSTATE ){
-#ifdef NDEBUG
- /* If we are not debugging and the reduce action popped at least
- ** one element off the stack, then we can push the new element back
- ** onto the stack here, and skip the stack overflow test in yy_shift().
- ** That gives a significant speed improvement. */
- if( yysize ){
- yypParser->yyidx++;
- yymsp -= yysize-1;
- yymsp->stateno = yyact;
- yymsp->major = yygoto;
- yymsp->minor = yygotominor;
- }else
-#endif
- {
- yy_shift(yypParser,yyact,yygoto,&yygotominor);
- }
- }else{
- assert( yyact == YYNSTATE + YYNRULE + 1 );
- yy_accept(yypParser);
- }
-}
-
-/*
-** The following code executes when the parse fails
-*/
-static void yy_parse_failed(
- yyParser *yypParser /* The parser */
-){
- ParseARG_FETCH;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will be executed whenever the
- ** parser fails */
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/*
-** The following code executes when a syntax error first occurs.
-*/
-static void yy_syntax_error(
- yyParser *yypParser, /* The parser */
- int yymajor, /* The major type of the error token */
- YYMINORTYPE yyminor /* The minor type of the error token */
-){
- ParseARG_FETCH;
-#define TOKEN (yyminor.yy0)
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/*
-** The following is executed when the parser accepts
-*/
-static void yy_accept(
- yyParser *yypParser /* The parser */
-){
- ParseARG_FETCH;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will be executed whenever the
- ** parser accepts */
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/* The main parser program.
-** The first argument is a pointer to a structure obtained from
-** "ParseAlloc" which describes the current state of the parser.
-** The second argument is the major token number. The third is
-** the minor token. The fourth optional argument is whatever the
-** user wants (and specified in the grammar) and is available for
-** use by the action routines.
-**
-** Inputs:
-**
-** - A pointer to the parser (an opaque structure.)
-**
- The major token number.
-**
- The minor token number.
-**
- An option argument of a grammar-specified type.
-**
-**
-** Outputs:
-** None.
-*/
-void Parse(
- void *yyp, /* The parser */
- int yymajor, /* The major token code number */
- ParseTOKENTYPE yyminor /* The value for the token */
- ParseARG_PDECL /* Optional %extra_argument parameter */
-){
- YYMINORTYPE yyminorunion;
- int yyact; /* The parser action. */
- int yyendofinput; /* True if we are at the end of input */
-#ifdef YYERRORSYMBOL
- int yyerrorhit = 0; /* True if yymajor has invoked an error */
-#endif
- yyParser *yypParser; /* The parser */
-
- /* (re)initialize the parser, if necessary */
- yypParser = (yyParser*)yyp;
- if( yypParser->yyidx<0 ){
-#if YYSTACKDEPTH<=0
- if( yypParser->yystksz <=0 ){
- memset(&yyminorunion, 0, sizeof(yyminorunion));
- yyStackOverflow(yypParser, &yyminorunion);
- return;
- }
-#endif
- yypParser->yyidx = 0;
- yypParser->yyerrcnt = -1;
- yypParser->yystack[0].stateno = 0;
- yypParser->yystack[0].major = 0;
- }
- yyminorunion.yy0 = yyminor;
- yyendofinput = (yymajor==0);
- ParseARG_STORE;
-
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
- }
-#endif
-
- do{
- yyact = yy_find_shift_action(yypParser,yymajor);
- if( yyactyyerrcnt--;
- yymajor = YYNOCODE;
- }else if( yyact < YYNSTATE + YYNRULE ){
- yy_reduce(yypParser,yyact-YYNSTATE);
- }else{
- assert( yyact == YY_ERROR_ACTION );
-#ifdef YYERRORSYMBOL
- int yymx;
-#endif
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
- }
-#endif
-#ifdef YYERRORSYMBOL
- /* A syntax error has occurred.
- ** The response to an error depends upon whether or not the
- ** grammar defines an error token "ERROR".
- **
- ** This is what we do if the grammar does define ERROR:
- **
- ** * Call the %syntax_error function.
- **
- ** * Begin popping the stack until we enter a state where
- ** it is legal to shift the error symbol, then shift
- ** the error symbol.
- **
- ** * Set the error count to three.
- **
- ** * Begin accepting and shifting new tokens. No new error
- ** processing will occur until three tokens have been
- ** shifted successfully.
- **
- */
- if( yypParser->yyerrcnt<0 ){
- yy_syntax_error(yypParser,yymajor,yyminorunion);
- }
- yymx = yypParser->yystack[yypParser->yyidx].major;
- if( yymx==YYERRORSYMBOL || yyerrorhit ){
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sDiscard input token %s\n",
- yyTracePrompt,yyTokenName[yymajor]);
- }
-#endif
- yy_destructor(yymajor,&yyminorunion);
- yymajor = YYNOCODE;
- }else{
- while(
- yypParser->yyidx >= 0 &&
- yymx != YYERRORSYMBOL &&
- (yyact = yy_find_reduce_action(
- yypParser->yystack[yypParser->yyidx].stateno,
- YYERRORSYMBOL)) >= YYNSTATE
- ){
- yy_pop_parser_stack(yypParser);
- }
- if( yypParser->yyidx < 0 || yymajor==0 ){
- yy_destructor(yymajor,&yyminorunion);
- yy_parse_failed(yypParser);
- yymajor = YYNOCODE;
- }else if( yymx!=YYERRORSYMBOL ){
- YYMINORTYPE u2;
- u2.YYERRSYMDT = 0;
- yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
- }
- }
- yypParser->yyerrcnt = 3;
- yyerrorhit = 1;
-#else /* YYERRORSYMBOL is not defined */
- /* This is what we do if the grammar does not define ERROR:
- **
- ** * Report an error message, and throw away the input token.
- **
- ** * If the input token is $, then fail the parse.
- **
- ** As before, subsequent error messages are suppressed until
- ** three input tokens have been successfully shifted.
- */
- if( yypParser->yyerrcnt<=0 ){
- yy_syntax_error(yypParser,yymajor,yyminorunion);
- }
- yypParser->yyerrcnt = 3;
- yy_destructor(yymajor,&yyminorunion);
- if( yyendofinput ){
- yy_parse_failed(yypParser);
- }
- yymajor = YYNOCODE;
-#endif
- }
- }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
- return;
-}
Index: MultiSource/Applications/lemon/lighttpd_COPYING
===================================================================
--- MultiSource/Applications/lemon/lighttpd_COPYING
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-Copyright (c) 2004, Jan Kneschke, incremental
- All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-- Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-- Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-- Neither the name of the 'incremental' nor the names of its contributors may
- be used to endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGE.
-
Index: MultiSource/Applications/lemon/lighttpd_configparser.y
===================================================================
--- MultiSource/Applications/lemon/lighttpd_configparser.y
+++ /dev/null
@@ -1,564 +0,0 @@
-%token_prefix TK_
-%extra_argument {config_t *ctx}
-%name configparser
-
-%include {
-#include
-#include
-#include
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "configfile.h"
-#include "buffer.h"
-#include "array.h"
-
-static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
- if (isnew) {
- dc->context_ndx = ctx->all_configs->used;
- assert(dc->context_ndx > ctx->current->context_ndx);
- array_insert_unique(ctx->all_configs, (data_unset *)dc);
- dc->parent = ctx->current;
- array_insert_unique(dc->parent->childs, (data_unset *)dc);
- }
- array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
- ctx->current = dc;
-}
-
-static data_config *configparser_pop(config_t *ctx) {
- data_config *old = ctx->current;
- ctx->current = (data_config *) array_pop(ctx->configs_stack);
- return old;
-}
-
-/* return a copied variable */
-static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
- data_unset *du;
- data_config *dc;
-
-#if 0
- fprintf(stderr, "get var %s\n", key->ptr);
-#endif
- for (dc = ctx->current; dc; dc = dc->parent) {
-#if 0
- fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
- array_print(dc->value, 0);
-#endif
- if (NULL != (du = array_get_element(dc->value, key->ptr))) {
- return du->copy(du);
- }
- }
- return NULL;
-}
-
-/* op1 is to be eat/return by this function if success, op1->key is not cared
- op2 is left untouch, unreferenced
- */
-data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
- /* type mismatch */
- if (op1->type != op2->type) {
- if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
- data_string *ds = (data_string *)op1;
- buffer_append_long(ds->value, ((data_integer*)op2)->value);
- return op1;
- } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
- data_string *ds = data_string_init();
- buffer_append_long(ds->value, ((data_integer*)op1)->value);
- buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
- op1->free(op1);
- return (data_unset *)ds;
- } else {
- fprintf(stderr, "data type mismatch, cannot be merge\n");
- return NULL;
- }
- }
-
- switch (op1->type) {
- case TYPE_STRING:
- buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
- break;
- case TYPE_INTEGER:
- ((data_integer *)op1)->value += ((data_integer *)op2)->value;
- break;
- case TYPE_ARRAY: {
- array *dst = ((data_array *)op1)->value;
- array *src = ((data_array *)op2)->value;
- data_unset *du;
- size_t i;
-
- for (i = 0; i < src->used; i ++) {
- du = (data_unset *)src->data[i];
- if (du) {
- array_insert_unique(dst, du->copy(du));
- }
- }
- break;
- default:
- assert(0);
- break;
- }
- }
- return op1;
-}
-
-}
-
-%parse_failure {
- ctx->ok = 0;
-}
-
-input ::= metalines.
-metalines ::= metalines metaline.
-metalines ::= .
-metaline ::= varline.
-metaline ::= global.
-metaline ::= condlines(A) EOL. { A = NULL; }
-metaline ::= include.
-metaline ::= include_shell.
-metaline ::= EOL.
-
-%type value {data_unset *}
-%type expression {data_unset *}
-%type aelement {data_unset *}
-%type condline {data_config *}
-%type condlines {data_config *}
-%type global {data_config *}
-%type aelements {array *}
-%type array {array *}
-%type key {buffer *}
-%type stringop {buffer *}
-
-%type cond {config_cond_t }
-
-%destructor value { $$->free($$); }
-%destructor expression { $$->free($$); }
-%destructor aelement { $$->free($$); }
-%destructor aelements { array_free($$); }
-%destructor array { array_free($$); }
-%destructor key { buffer_free($$); }
-%destructor stringop { buffer_free($$); }
-
-%token_type {buffer *}
-%token_destructor { buffer_free($$); }
-
-varline ::= key(A) ASSIGN expression(B). {
- if (ctx->ok) {
- buffer_copy_string_buffer(B->key, A);
- if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
- fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, A->ptr);
- ctx->ok = 0;
- } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
- array_insert_unique(ctx->current->value, B);
- B = NULL;
- } else {
- fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, B->key->ptr);
- ctx->ok = 0;
- B->free(B);
- B = NULL;
- }
- }
- buffer_free(A);
- A = NULL;
-}
-
-varline ::= key(A) APPEND expression(B). {
- array *vars = ctx->current->value;
- data_unset *du;
-
- if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
- fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, A->ptr);
- ctx->ok = 0;
- } else if (NULL != (du = array_get_element(vars, A->ptr))) {
- /* exists in current block */
- du = configparser_merge_data(du, B);
- if (NULL == du) {
- ctx->ok = 0;
- }
- else {
- buffer_copy_string_buffer(du->key, A);
- array_replace(vars, du);
- }
- B->free(B);
- } else if (NULL != (du = configparser_get_variable(ctx, A))) {
- du = configparser_merge_data(du, B);
- if (NULL == du) {
- ctx->ok = 0;
- du->free(du);
- }
- else {
- buffer_copy_string_buffer(du->key, A);
- array_insert_unique(ctx->current->value, du);
- }
- B->free(B);
- } else {
- buffer_copy_string_buffer(B->key, A);
- array_insert_unique(ctx->current->value, B);
- }
- buffer_free(A);
- A = NULL;
- B = NULL;
-}
-
-key(A) ::= LKEY(B). {
- if (strchr(B->ptr, '.') == NULL) {
- A = buffer_init_string("var.");
- buffer_append_string_buffer(A, B);
- buffer_free(B);
- B = NULL;
- } else {
- A = B;
- B = NULL;
- }
-}
-
-expression(A) ::= expression(B) PLUS value(C). {
- A = configparser_merge_data(B, C);
- if (NULL == A) {
- ctx->ok = 0;
- }
- B = NULL;
- C->free(C);
- C = NULL;
-}
-
-expression(A) ::= value(B). {
- A = B;
- B = NULL;
-}
-
-value(A) ::= key(B). {
- A = NULL;
- if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
- char *env;
-
- if (NULL != (env = getenv(B->ptr + 4))) {
- data_string *ds;
- ds = data_string_init();
- buffer_append_string(ds->value, env);
- A = (data_unset *)ds;
- }
- else {
- fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
- ctx->ok = 0;
- }
- } else if (NULL == (A = configparser_get_variable(ctx, B))) {
- fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
- ctx->ok = 0;
- }
- if (!A) {
- /* make a dummy so it won't crash */
- A = (data_unset *)data_string_init();
- }
- buffer_free(B);
- B = NULL;
-}
-
-value(A) ::= STRING(B). {
- A = (data_unset *)data_string_init();
- buffer_copy_string_buffer(((data_string *)(A))->value, B);
- buffer_free(B);
- B = NULL;
-}
-
-value(A) ::= INTEGER(B). {
- A = (data_unset *)data_integer_init();
- ((data_integer *)(A))->value = strtol(B->ptr, NULL, 10);
- buffer_free(B);
- B = NULL;
-}
-value(A) ::= array(B). {
- A = (data_unset *)data_array_init();
- array_free(((data_array *)(A))->value);
- ((data_array *)(A))->value = B;
- B = NULL;
-}
-array(A) ::= LPARAN RPARAN. {
- A = array_init();
-}
-array(A) ::= LPARAN aelements(B) RPARAN. {
- A = B;
- B = NULL;
-}
-
-aelements(A) ::= aelements(C) COMMA aelement(B). {
- if (buffer_is_empty(B->key) ||
- NULL == array_get_element(C, B->key->ptr)) {
- array_insert_unique(C, B);
- B = NULL;
- } else {
- fprintf(stderr, "Duplicate array-key: %s\n",
- B->key->ptr);
- ctx->ok = 0;
- B->free(B);
- B = NULL;
- }
-
- A = C;
- C = NULL;
-}
-
-aelements(A) ::= aelements(C) COMMA. {
- A = C;
- C = NULL;
-}
-
-aelements(A) ::= aelement(B). {
- A = array_init();
- array_insert_unique(A, B);
- B = NULL;
-}
-
-aelement(A) ::= expression(B). {
- A = B;
- B = NULL;
-}
-aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
- buffer_copy_string_buffer(C->key, B);
- buffer_free(B);
- B = NULL;
-
- A = C;
- C = NULL;
-}
-
-eols ::= EOL.
-eols ::= .
-
-globalstart ::= GLOBAL. {
- data_config *dc;
- dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
- assert(dc);
- configparser_push(ctx, dc, 0);
-}
-
-global(A) ::= globalstart LCURLY metalines RCURLY. {
- data_config *cur;
-
- cur = ctx->current;
- configparser_pop(ctx);
-
- assert(cur && ctx->current);
-
- A = cur;
-}
-
-condlines(A) ::= condlines(B) eols ELSE condline(C). {
- assert(B->context_ndx < C->context_ndx);
- C->prev = B;
- B->next = C;
- A = C;
- B = NULL;
- C = NULL;
-}
-
-condlines(A) ::= condline(B). {
- A = B;
- B = NULL;
-}
-
-condline(A) ::= context LCURLY metalines RCURLY. {
- data_config *cur;
-
- cur = ctx->current;
- configparser_pop(ctx);
-
- assert(cur && ctx->current);
-
- A = cur;
-}
-
-context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
- data_config *dc;
- buffer *b, *rvalue, *op;
-
- if (ctx->ok && D->type != TYPE_STRING) {
- fprintf(stderr, "rvalue must be string");
- ctx->ok = 0;
- }
-
- switch(E) {
- case CONFIG_COND_NE:
- op = buffer_init_string("!=");
- break;
- case CONFIG_COND_EQ:
- op = buffer_init_string("==");
- break;
- case CONFIG_COND_NOMATCH:
- op = buffer_init_string("!~");
- break;
- case CONFIG_COND_MATCH:
- op = buffer_init_string("=~");
- break;
- default:
- assert(0);
- return;
- }
-
- b = buffer_init();
- buffer_copy_string_buffer(b, ctx->current->key);
- buffer_append_string(b, "/");
- buffer_append_string_buffer(b, B);
- buffer_append_string_buffer(b, C);
- buffer_append_string_buffer(b, op);
- rvalue = ((data_string*)D)->value;
- buffer_append_string_buffer(b, rvalue);
-
- if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
- configparser_push(ctx, dc, 0);
- } else {
- struct {
- comp_key_t comp;
- char *comp_key;
- size_t len;
- } comps[] = {
- { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) },
- { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
- { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
- { COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) },
- { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
- { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
- { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
- { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
- { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) },
- { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
- { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") },
- { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
- { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
- { COMP_UNSET, NULL, 0 },
- };
- size_t i;
-
- dc = data_config_init();
-
- buffer_copy_string_buffer(dc->key, b);
- buffer_copy_string_buffer(dc->op, op);
- buffer_copy_string_buffer(dc->comp_key, B);
- buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
- buffer_append_string_buffer(dc->comp_key, C);
- buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
- dc->cond = E;
-
- for (i = 0; comps[i].comp_key; i ++) {
- if (buffer_is_equal_string(
- dc->comp_key, comps[i].comp_key, comps[i].len)) {
- dc->comp = comps[i].comp;
- break;
- }
- }
- if (COMP_UNSET == dc->comp) {
- fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
- ctx->ok = 0;
- }
-
- switch(E) {
- case CONFIG_COND_NE:
- case CONFIG_COND_EQ:
- dc->string = buffer_init_buffer(rvalue);
- break;
- case CONFIG_COND_NOMATCH:
- case CONFIG_COND_MATCH: {
-#ifdef HAVE_PCRE_H
- const char *errptr;
- int erroff;
-
- if (NULL == (dc->regex =
- pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
- dc->string = buffer_init_string(errptr);
- dc->cond = CONFIG_COND_UNSET;
-
- fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
- rvalue->ptr, errptr, erroff);
-
- ctx->ok = 0;
- } else if (NULL == (dc->regex_study =
- pcre_study(dc->regex, 0, &errptr)) &&
- errptr != NULL) {
- fprintf(stderr, "studying regex failed: %s -> %s\n",
- rvalue->ptr, errptr);
- ctx->ok = 0;
- } else {
- dc->string = buffer_init_buffer(rvalue);
- }
-#else
- fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
- "(perhaps just a missing pcre-devel package ?) \n",
- B->ptr, C->ptr);
- ctx->ok = 0;
-#endif
- break;
- }
-
- default:
- fprintf(stderr, "unknown condition for $%s[%s]\n",
- B->ptr, C->ptr);
- ctx->ok = 0;
- break;
- }
-
- configparser_push(ctx, dc, 1);
- }
-
- buffer_free(b);
- buffer_free(op);
- buffer_free(B);
- B = NULL;
- buffer_free(C);
- C = NULL;
- D->free(D);
- D = NULL;
-}
-cond(A) ::= EQ. {
- A = CONFIG_COND_EQ;
-}
-cond(A) ::= MATCH. {
- A = CONFIG_COND_MATCH;
-}
-cond(A) ::= NE. {
- A = CONFIG_COND_NE;
-}
-cond(A) ::= NOMATCH. {
- A = CONFIG_COND_NOMATCH;
-}
-
-stringop(A) ::= expression(B). {
- A = NULL;
- if (ctx->ok) {
- if (B->type == TYPE_STRING) {
- A = buffer_init_buffer(((data_string*)B)->value);
- } else if (B->type == TYPE_INTEGER) {
- A = buffer_init();
- buffer_copy_long(A, ((data_integer *)B)->value);
- } else {
- fprintf(stderr, "operand must be string");
- ctx->ok = 0;
- }
- }
- B->free(B);
- B = NULL;
-}
-
-include ::= INCLUDE stringop(A). {
- if (ctx->ok) {
- if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
- ctx->ok = 0;
- }
- buffer_free(A);
- A = NULL;
- }
-}
-
-include_shell ::= INCLUDE_SHELL stringop(A). {
- if (ctx->ok) {
- if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
- ctx->ok = 0;
- }
- buffer_free(A);
- A = NULL;
- }
-}
Index: MultiSource/Applications/lemon/lighttpd_mod_ssi_exprparser.y
===================================================================
--- MultiSource/Applications/lemon/lighttpd_mod_ssi_exprparser.y
+++ /dev/null
@@ -1,121 +0,0 @@
-%token_prefix TK_
-%token_type {buffer *}
-%extra_argument {ssi_ctx_t *ctx}
-%name ssiexprparser
-
-%include {
-#include
-#include
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "mod_ssi_expr.h"
-#include "buffer.h"
-}
-
-%parse_failure {
- ctx->ok = 0;
-}
-
-%type expr { ssi_val_t * }
-%type value { buffer * }
-%type exprline { ssi_val_t * }
-%type cond { int }
-%token_destructor { buffer_free($$); }
-
-%left AND.
-%left OR.
-%nonassoc EQ NE GT GE LT LE.
-%right NOT.
-
-input ::= exprline(B). {
- ctx->val.bo = ssi_val_tobool(B);
- ctx->val.type = SSI_TYPE_BOOL;
-
- ssi_val_free(B);
-}
-
-exprline(A) ::= expr(B) cond(C) expr(D). {
- int cmp;
-
- if (B->type == SSI_TYPE_STRING &&
- D->type == SSI_TYPE_STRING) {
- cmp = strcmp(B->str->ptr, D->str->ptr);
- } else {
- cmp = ssi_val_tobool(B) - ssi_val_tobool(D);
- }
-
- A = B;
-
- switch(C) {
- case SSI_COND_EQ: A->bo = (cmp == 0) ? 1 : 0; break;
- case SSI_COND_NE: A->bo = (cmp != 0) ? 1 : 0; break;
- case SSI_COND_GE: A->bo = (cmp >= 0) ? 1 : 0; break;
- case SSI_COND_GT: A->bo = (cmp > 0) ? 1 : 0; break;
- case SSI_COND_LE: A->bo = (cmp <= 0) ? 1 : 0; break;
- case SSI_COND_LT: A->bo = (cmp < 0) ? 1 : 0; break;
- }
-
- A->type = SSI_TYPE_BOOL;
-
- ssi_val_free(D);
-}
-exprline(A) ::= expr(B). {
- A = B;
-}
-expr(A) ::= expr(B) AND expr(C). {
- int e;
-
- e = ssi_val_tobool(B) && ssi_val_tobool(C);
-
- A = B;
- A->bo = e;
- A->type = SSI_TYPE_BOOL;
- ssi_val_free(C);
-}
-
-expr(A) ::= expr(B) OR expr(C). {
- int e;
-
- e = ssi_val_tobool(B) || ssi_val_tobool(C);
-
- A = B;
- A->bo = e;
- A->type = SSI_TYPE_BOOL;
- ssi_val_free(C);
-}
-
-expr(A) ::= NOT expr(B). {
- int e;
-
- e = !ssi_val_tobool(B);
-
- A = B;
- A->bo = e;
- A->type = SSI_TYPE_BOOL;
-}
-expr(A) ::= LPARAN exprline(B) RPARAN. {
- A = B;
-}
-
-expr(A) ::= value(B). {
- A = ssi_val_init();
- A->str = B;
- A->type = SSI_TYPE_STRING;
-}
-
-value(A) ::= VALUE(B). {
- A = buffer_init_string(B->ptr);
-}
-
-value(A) ::= value(B) VALUE(C). {
- A = B;
- buffer_append_string_buffer(A, C);
-}
-
-cond(A) ::= EQ. { A = SSI_COND_EQ; }
-cond(A) ::= NE. { A = SSI_COND_NE; }
-cond(A) ::= LE. { A = SSI_COND_LE; }
-cond(A) ::= GE. { A = SSI_COND_GE; }
-cond(A) ::= LT. { A = SSI_COND_LT; }
-cond(A) ::= GT. { A = SSI_COND_GT; }
Index: MultiSource/Applications/lemon/parse.y
===================================================================
--- MultiSource/Applications/lemon/parse.y
+++ /dev/null
@@ -1,1114 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains SQLite's grammar for SQL. Process this file
-** using the lemon parser generator to generate C code that runs
-** the parser. Lemon will also generate a header file containing
-** numeric codes for all of the tokens.
-**
-** @(#) $Id: parse.y,v 1.240 2008/01/22 23:37:10 drh Exp $
-*/
-
-// All token codes are small integers with #defines that begin with "TK_"
-%token_prefix TK_
-
-// The type of the data attached to each token is Token. This is also the
-// default type for non-terminals.
-//
-%token_type {Token}
-%default_type {Token}
-
-// The generated parser function takes a 4th argument as follows:
-%extra_argument {Parse *pParse}
-
-// This code runs whenever there is a syntax error
-//
-%syntax_error {
- assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
- pParse->parseError = 1;
-}
-%stack_overflow {
- sqlite3ErrorMsg(pParse, "parser stack overflow");
- pParse->parseError = 1;
-}
-
-// The name of the generated procedure that implements the parser
-// is as follows:
-%name sqlite3Parser
-
-// The following text is included near the beginning of the C source
-// code file that implements the parser.
-//
-%include {
-#include "sqliteInt.h"
-
-/*
-** An instance of this structure holds information about the
-** LIMIT clause of a SELECT statement.
-*/
-struct LimitVal {
- Expr *pLimit; /* The LIMIT expression. NULL if there is no limit */
- Expr *pOffset; /* The OFFSET expression. NULL if there is none */
-};
-
-/*
-** An instance of this structure is used to store the LIKE,
-** GLOB, NOT LIKE, and NOT GLOB operators.
-*/
-struct LikeOp {
- Token eOperator; /* "like" or "glob" or "regexp" */
- int not; /* True if the NOT keyword is present */
-};
-
-/*
-** An instance of the following structure describes the event of a
-** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT,
-** TK_DELETE, or TK_INSTEAD. If the event is of the form
-**
-** UPDATE ON (a,b,c)
-**
-** Then the "b" IdList records the list "a,b,c".
-*/
-struct TrigEvent { int a; IdList * b; };
-
-/*
-** An instance of this structure holds the ATTACH key and the key type.
-*/
-struct AttachKey { int type; Token key; };
-
-} // end %include
-
-// Input is a single SQL command
-input ::= cmdlist.
-cmdlist ::= cmdlist ecmd.
-cmdlist ::= ecmd.
-cmdx ::= cmd. { sqlite3FinishCoding(pParse); }
-ecmd ::= SEMI.
-ecmd ::= explain cmdx SEMI.
-explain ::= . { sqlite3BeginParse(pParse, 0); }
-%ifndef SQLITE_OMIT_EXPLAIN
-explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
-explain ::= EXPLAIN QUERY PLAN. { sqlite3BeginParse(pParse, 2); }
-%endif SQLITE_OMIT_EXPLAIN
-
-///////////////////// Begin and end transactions. ////////////////////////////
-//
-
-cmd ::= BEGIN transtype(Y) trans_opt. {sqlite3BeginTransaction(pParse, Y);}
-trans_opt ::= .
-trans_opt ::= TRANSACTION.
-trans_opt ::= TRANSACTION nm.
-%type transtype {int}
-transtype(A) ::= . {A = TK_DEFERRED;}
-transtype(A) ::= DEFERRED(X). {A = @X;}
-transtype(A) ::= IMMEDIATE(X). {A = @X;}
-transtype(A) ::= EXCLUSIVE(X). {A = @X;}
-cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);}
-cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);}
-cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
-
-///////////////////// The CREATE TABLE statement ////////////////////////////
-//
-cmd ::= create_table create_table_args.
-create_table ::= CREATE temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
- sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
-}
-%type ifnotexists {int}
-ifnotexists(A) ::= . {A = 0;}
-ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
-%type temp {int}
-%ifndef SQLITE_OMIT_TEMPDB
-temp(A) ::= TEMP. {A = 1;}
-%endif SQLITE_OMIT_TEMPDB
-temp(A) ::= . {A = 0;}
-create_table_args ::= LP columnlist conslist_opt(X) RP(Y). {
- sqlite3EndTable(pParse,&X,&Y,0);
-}
-create_table_args ::= AS select(S). {
- sqlite3EndTable(pParse,0,0,S);
- sqlite3SelectDelete(S);
-}
-columnlist ::= columnlist COMMA column.
-columnlist ::= column.
-
-// A "column" is a complete description of a single column in a
-// CREATE TABLE statement. This includes the column name, its
-// datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES,
-// NOT NULL and so forth.
-//
-column(A) ::= columnid(X) type carglist. {
- A.z = X.z;
- A.n = (pParse->sLastToken.z-X.z) + pParse->sLastToken.n;
-}
-columnid(A) ::= nm(X). {
- sqlite3AddColumn(pParse,&X);
- A = X;
-}
-
-
-// An IDENTIFIER can be a generic identifier, or one of several
-// keywords. Any non-standard keyword can also be an identifier.
-//
-%type id {Token}
-id(A) ::= ID(X). {A = X;}
-
-// The following directive causes tokens ABORT, AFTER, ASC, etc. to
-// fallback to ID if they will not parse as their original value.
-// This obviates the need for the "id" nonterminal.
-//
-%fallback ID
- ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
- DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
- IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN
- QUERY KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW
- TEMP TRIGGER VACUUM VIEW VIRTUAL
-%ifdef SQLITE_OMIT_COMPOUND_SELECT
- EXCEPT INTERSECT UNION
-%endif SQLITE_OMIT_COMPOUND_SELECT
- REINDEX RENAME CTIME_KW IF
- .
-%wildcard ANY.
-
-// Define operator precedence early so that this is the first occurance
-// of the operator tokens in the grammer. Keeping the operators together
-// causes them to be assigned integer values that are close together,
-// which keeps parser tables smaller.
-//
-// The token values assigned to these symbols is determined by the order
-// in which lemon first sees them. It must be the case that ISNULL/NOTNULL,
-// NE/EQ, GT/LE, and GE/LT are separated by only a single value. See
-// the sqlite3ExprIfFalse() routine for additional information on this
-// constraint.
-//
-%left OR.
-%left AND.
-%right NOT.
-%left IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ.
-%left GT LE LT GE.
-%right ESCAPE.
-%left BITAND BITOR LSHIFT RSHIFT.
-%left PLUS MINUS.
-%left STAR SLASH REM.
-%left CONCAT.
-%left COLLATE.
-%right UMINUS UPLUS BITNOT.
-
-// And "ids" is an identifer-or-string.
-//
-%type ids {Token}
-ids(A) ::= ID|STRING(X). {A = X;}
-
-// The name of a column or table can be any of the following:
-//
-%type nm {Token}
-nm(A) ::= ID(X). {A = X;}
-nm(A) ::= STRING(X). {A = X;}
-nm(A) ::= JOIN_KW(X). {A = X;}
-
-// A typetoken is really one or more tokens that form a type name such
-// as can be found after the column name in a CREATE TABLE statement.
-// Multiple tokens are concatenated to form the value of the typetoken.
-//
-%type typetoken {Token}
-type ::= .
-type ::= typetoken(X). {sqlite3AddColumnType(pParse,&X);}
-typetoken(A) ::= typename(X). {A = X;}
-typetoken(A) ::= typename(X) LP signed RP(Y). {
- A.z = X.z;
- A.n = &Y.z[Y.n] - X.z;
-}
-typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). {
- A.z = X.z;
- A.n = &Y.z[Y.n] - X.z;
-}
-%type typename {Token}
-typename(A) ::= ids(X). {A = X;}
-typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(Y.z-X.z);}
-signed ::= plus_num.
-signed ::= minus_num.
-
-// "carglist" is a list of additional constraints that come after the
-// column name and column type in a CREATE TABLE statement.
-//
-carglist ::= carglist carg.
-carglist ::= .
-carg ::= CONSTRAINT nm ccons.
-carg ::= ccons.
-ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
-ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
-ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
-ccons ::= DEFAULT MINUS term(X). {
- Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0, 0);
- sqlite3AddDefaultValue(pParse,p);
-}
-ccons ::= DEFAULT id(X). {
- Expr *p = sqlite3PExpr(pParse, TK_STRING, 0, 0, &X);
- sqlite3AddDefaultValue(pParse,p);
-}
-
-// In addition to the type name, we also care about the primary key and
-// UNIQUE constraints.
-//
-ccons ::= NULL onconf.
-ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);}
-ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
- {sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
-ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);}
-ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X);}
-ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
- {sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
-ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
-ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);}
-
-// The optional AUTOINCREMENT keyword
-%type autoinc {int}
-autoinc(X) ::= . {X = 0;}
-autoinc(X) ::= AUTOINCR. {X = 1;}
-
-// The next group of rules parses the arguments to a REFERENCES clause
-// that determine if the referential integrity checking is deferred or
-// or immediate and which determine what action to take if a ref-integ
-// check fails.
-//
-%type refargs {int}
-refargs(A) ::= . { A = OE_Restrict * 0x010101; }
-refargs(A) ::= refargs(X) refarg(Y). { A = (X & Y.mask) | Y.value; }
-%type refarg {struct {int value; int mask;}}
-refarg(A) ::= MATCH nm. { A.value = 0; A.mask = 0x000000; }
-refarg(A) ::= ON DELETE refact(X). { A.value = X; A.mask = 0x0000ff; }
-refarg(A) ::= ON UPDATE refact(X). { A.value = X<<8; A.mask = 0x00ff00; }
-refarg(A) ::= ON INSERT refact(X). { A.value = X<<16; A.mask = 0xff0000; }
-%type refact {int}
-refact(A) ::= SET NULL. { A = OE_SetNull; }
-refact(A) ::= SET DEFAULT. { A = OE_SetDflt; }
-refact(A) ::= CASCADE. { A = OE_Cascade; }
-refact(A) ::= RESTRICT. { A = OE_Restrict; }
-%type defer_subclause {int}
-defer_subclause(A) ::= NOT DEFERRABLE init_deferred_pred_opt(X). {A = X;}
-defer_subclause(A) ::= DEFERRABLE init_deferred_pred_opt(X). {A = X;}
-%type init_deferred_pred_opt {int}
-init_deferred_pred_opt(A) ::= . {A = 0;}
-init_deferred_pred_opt(A) ::= INITIALLY DEFERRED. {A = 1;}
-init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;}
-
-// For the time being, the only constraint we care about is the primary
-// key and UNIQUE. Both create indices.
-//
-conslist_opt(A) ::= . {A.n = 0; A.z = 0;}
-conslist_opt(A) ::= COMMA(X) conslist. {A = X;}
-conslist ::= conslist COMMA tcons.
-conslist ::= conslist tcons.
-conslist ::= tcons.
-tcons ::= CONSTRAINT nm.
-tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R).
- {sqlite3AddPrimaryKey(pParse,X,R,I,0);}
-tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
- {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0);}
-tcons ::= CHECK LP expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E);}
-tcons ::= FOREIGN KEY LP idxlist(FA) RP
- REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
- sqlite3CreateForeignKey(pParse, FA, &T, TA, R);
- sqlite3DeferForeignKey(pParse, D);
-}
-%type defer_subclause_opt {int}
-defer_subclause_opt(A) ::= . {A = 0;}
-defer_subclause_opt(A) ::= defer_subclause(X). {A = X;}
-
-// The following is a non-standard extension that allows us to declare the
-// default behavior when there is a constraint conflict.
-//
-%type onconf {int}
-%type orconf {int}
-%type resolvetype {int}
-onconf(A) ::= . {A = OE_Default;}
-onconf(A) ::= ON CONFLICT resolvetype(X). {A = X;}
-orconf(A) ::= . {A = OE_Default;}
-orconf(A) ::= OR resolvetype(X). {A = X;}
-resolvetype(A) ::= raisetype(X). {A = X;}
-resolvetype(A) ::= IGNORE. {A = OE_Ignore;}
-resolvetype(A) ::= REPLACE. {A = OE_Replace;}
-
-////////////////////////// The DROP TABLE /////////////////////////////////////
-//
-cmd ::= DROP TABLE ifexists(E) fullname(X). {
- sqlite3DropTable(pParse, X, 0, E);
-}
-%type ifexists {int}
-ifexists(A) ::= IF EXISTS. {A = 1;}
-ifexists(A) ::= . {A = 0;}
-
-///////////////////// The CREATE VIEW statement /////////////////////////////
-//
-%ifndef SQLITE_OMIT_VIEW
-cmd ::= CREATE(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
- sqlite3CreateView(pParse, &X, &Y, &Z, S, T, E);
-}
-cmd ::= DROP VIEW ifexists(E) fullname(X). {
- sqlite3DropTable(pParse, X, 1, E);
-}
-%endif SQLITE_OMIT_VIEW
-
-//////////////////////// The SELECT statement /////////////////////////////////
-//
-cmd ::= select(X). {
- SelectDest dest = {SRT_Callback, 0, 0};
- sqlite3Select(pParse, X, &dest, 0, 0, 0, 0);
- sqlite3SelectDelete(X);
-}
-
-%type select {Select*}
-%destructor select {sqlite3SelectDelete($$);}
-%type oneselect {Select*}
-%destructor oneselect {sqlite3SelectDelete($$);}
-
-select(A) ::= oneselect(X). {A = X;}
-%ifndef SQLITE_OMIT_COMPOUND_SELECT
-select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
- if( Z ){
- Z->op = Y;
- Z->pPrior = X;
- }else{
- sqlite3SelectDelete(X);
- }
- A = Z;
-}
-%type multiselect_op {int}
-multiselect_op(A) ::= UNION(OP). {A = @OP;}
-multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
-multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;}
-%endif SQLITE_OMIT_COMPOUND_SELECT
-oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
- groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
- A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
-}
-
-// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
-// present and false (0) if it is not.
-//
-%type distinct {int}
-distinct(A) ::= DISTINCT. {A = 1;}
-distinct(A) ::= ALL. {A = 0;}
-distinct(A) ::= . {A = 0;}
-
-// selcollist is a list of expressions that are to become the return
-// values of the SELECT statement. The "*" in statements like
-// "SELECT * FROM ..." is encoded as a special expression with an
-// opcode of TK_ALL.
-//
-%type selcollist {ExprList*}
-%destructor selcollist {sqlite3ExprListDelete($$);}
-%type sclp {ExprList*}
-%destructor sclp {sqlite3ExprListDelete($$);}
-sclp(A) ::= selcollist(X) COMMA. {A = X;}
-sclp(A) ::= . {A = 0;}
-selcollist(A) ::= sclp(P) expr(X) as(Y). {
- A = sqlite3ExprListAppend(pParse,P,X,Y.n?&Y:0);
-}
-selcollist(A) ::= sclp(P) STAR. {
- Expr *p = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
- A = sqlite3ExprListAppend(pParse, P, p, 0);
-}
-selcollist(A) ::= sclp(P) nm(X) DOT STAR. {
- Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
- Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
- Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
- A = sqlite3ExprListAppend(pParse,P, pDot, 0);
-}
-
-// An option "AS " phrase that can follow one of the expressions that
-// define the result set, or one of the tables in the FROM clause.
-//
-%type as {Token}
-as(X) ::= AS nm(Y). {X = Y;}
-as(X) ::= ids(Y). {X = Y;}
-as(X) ::= . {X.n = 0;}
-
-
-%type seltablist {SrcList*}
-%destructor seltablist {sqlite3SrcListDelete($$);}
-%type stl_prefix {SrcList*}
-%destructor stl_prefix {sqlite3SrcListDelete($$);}
-%type from {SrcList*}
-%destructor from {sqlite3SrcListDelete($$);}
-
-// A complete FROM clause.
-//
-from(A) ::= . {A = sqlite3DbMallocZero(pParse->db, sizeof(*A));}
-from(A) ::= FROM seltablist(X). {
- A = X;
- sqlite3SrcListShiftJoinType(A);
-}
-
-// "seltablist" is a "Select Table List" - the content of the FROM clause
-// in a SELECT statement. "stl_prefix" is a prefix of this list.
-//
-stl_prefix(A) ::= seltablist(X) joinop(Y). {
- A = X;
- if( A && A->nSrc>0 ) A->a[A->nSrc-1].jointype = Y;
-}
-stl_prefix(A) ::= . {A = 0;}
-seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
- A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U);
-}
-%ifndef SQLITE_OMIT_SUBQUERY
- seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
- as(Z) on_opt(N) using_opt(U). {
- A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,S,N,U);
- }
-
- // A seltablist_paren nonterminal represents anything in a FROM that
- // is contained inside parentheses. This can be either a subquery or
- // a grouping of table and subqueries.
- //
- %type seltablist_paren {Select*}
- %destructor seltablist_paren {sqlite3SelectDelete($$);}
- seltablist_paren(A) ::= select(S). {A = S;}
- seltablist_paren(A) ::= seltablist(F). {
- sqlite3SrcListShiftJoinType(F);
- A = sqlite3SelectNew(pParse,0,F,0,0,0,0,0,0,0);
- }
-%endif SQLITE_OMIT_SUBQUERY
-
-%type dbnm {Token}
-dbnm(A) ::= . {A.z=0; A.n=0;}
-dbnm(A) ::= DOT nm(X). {A = X;}
-
-%type fullname {SrcList*}
-%destructor fullname {sqlite3SrcListDelete($$);}
-fullname(A) ::= nm(X) dbnm(Y). {A = sqlite3SrcListAppend(pParse->db,0,&X,&Y);}
-
-%type joinop {int}
-%type joinop2 {int}
-joinop(X) ::= COMMA|JOIN. { X = JT_INNER; }
-joinop(X) ::= JOIN_KW(A) JOIN. { X = sqlite3JoinType(pParse,&A,0,0); }
-joinop(X) ::= JOIN_KW(A) nm(B) JOIN. { X = sqlite3JoinType(pParse,&A,&B,0); }
-joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
- { X = sqlite3JoinType(pParse,&A,&B,&C); }
-
-%type on_opt {Expr*}
-%destructor on_opt {sqlite3ExprDelete($$);}
-on_opt(N) ::= ON expr(E). {N = E;}
-on_opt(N) ::= . {N = 0;}
-
-%type using_opt {IdList*}
-%destructor using_opt {sqlite3IdListDelete($$);}
-using_opt(U) ::= USING LP inscollist(L) RP. {U = L;}
-using_opt(U) ::= . {U = 0;}
-
-
-%type orderby_opt {ExprList*}
-%destructor orderby_opt {sqlite3ExprListDelete($$);}
-%type sortlist {ExprList*}
-%destructor sortlist {sqlite3ExprListDelete($$);}
-%type sortitem {Expr*}
-%destructor sortitem {sqlite3ExprDelete($$);}
-
-orderby_opt(A) ::= . {A = 0;}
-orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
-sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). {
- A = sqlite3ExprListAppend(pParse,X,Y,0);
- if( A ) A->a[A->nExpr-1].sortOrder = Z;
-}
-sortlist(A) ::= sortitem(Y) sortorder(Z). {
- A = sqlite3ExprListAppend(pParse,0,Y,0);
- if( A && A->a ) A->a[0].sortOrder = Z;
-}
-sortitem(A) ::= expr(X). {A = X;}
-
-%type sortorder {int}
-
-sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;}
-sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
-sortorder(A) ::= . {A = SQLITE_SO_ASC;}
-
-%type groupby_opt {ExprList*}
-%destructor groupby_opt {sqlite3ExprListDelete($$);}
-groupby_opt(A) ::= . {A = 0;}
-groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;}
-
-%type having_opt {Expr*}
-%destructor having_opt {sqlite3ExprDelete($$);}
-having_opt(A) ::= . {A = 0;}
-having_opt(A) ::= HAVING expr(X). {A = X;}
-
-%type limit_opt {struct LimitVal}
-
-// The destructor for limit_opt will never fire in the current grammar.
-// The limit_opt non-terminal only occurs at the end of a single production
-// rule for SELECT statements. As soon as the rule that create the
-// limit_opt non-terminal reduces, the SELECT statement rule will also
-// reduce. So there is never a limit_opt non-terminal on the stack
-// except as a transient. So there is never anything to destroy.
-//
-//%destructor limit_opt {
-// sqlite3ExprDelete($$.pLimit);
-// sqlite3ExprDelete($$.pOffset);
-//}
-limit_opt(A) ::= . {A.pLimit = 0; A.pOffset = 0;}
-limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X; A.pOffset = 0;}
-limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).
- {A.pLimit = X; A.pOffset = Y;}
-limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
- {A.pOffset = X; A.pLimit = Y;}
-
-/////////////////////////// The DELETE statement /////////////////////////////
-//
-cmd ::= DELETE FROM fullname(X) where_opt(Y). {sqlite3DeleteFrom(pParse,X,Y);}
-
-%type where_opt {Expr*}
-%destructor where_opt {sqlite3ExprDelete($$);}
-
-where_opt(A) ::= . {A = 0;}
-where_opt(A) ::= WHERE expr(X). {A = X;}
-
-////////////////////////// The UPDATE command ////////////////////////////////
-//
-cmd ::= UPDATE orconf(R) fullname(X) SET setlist(Y) where_opt(Z). {
- sqlite3ExprListCheckLength(pParse,Y,SQLITE_MAX_COLUMN,"set list");
- sqlite3Update(pParse,X,Y,Z,R);
-}
-
-%type setlist {ExprList*}
-%destructor setlist {sqlite3ExprListDelete($$);}
-
-setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
- {A = sqlite3ExprListAppend(pParse,Z,Y,&X);}
-setlist(A) ::= nm(X) EQ expr(Y).
- {A = sqlite3ExprListAppend(pParse,0,Y,&X);}
-
-////////////////////////// The INSERT command /////////////////////////////////
-//
-cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F)
- VALUES LP itemlist(Y) RP.
- {sqlite3Insert(pParse, X, Y, 0, F, R);}
-cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S).
- {sqlite3Insert(pParse, X, 0, S, F, R);}
-cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
- {sqlite3Insert(pParse, X, 0, 0, F, R);}
-
-%type insert_cmd {int}
-insert_cmd(A) ::= INSERT orconf(R). {A = R;}
-insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
-
-
-%type itemlist {ExprList*}
-%destructor itemlist {sqlite3ExprListDelete($$);}
-
-itemlist(A) ::= itemlist(X) COMMA expr(Y).
- {A = sqlite3ExprListAppend(pParse,X,Y,0);}
-itemlist(A) ::= expr(X).
- {A = sqlite3ExprListAppend(pParse,0,X,0);}
-
-%type inscollist_opt {IdList*}
-%destructor inscollist_opt {sqlite3IdListDelete($$);}
-%type inscollist {IdList*}
-%destructor inscollist {sqlite3IdListDelete($$);}
-
-inscollist_opt(A) ::= . {A = 0;}
-inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;}
-inscollist(A) ::= inscollist(X) COMMA nm(Y).
- {A = sqlite3IdListAppend(pParse->db,X,&Y);}
-inscollist(A) ::= nm(Y).
- {A = sqlite3IdListAppend(pParse->db,0,&Y);}
-
-/////////////////////////// Expression Processing /////////////////////////////
-//
-
-%type expr {Expr*}
-%destructor expr {sqlite3ExprDelete($$);}
-%type term {Expr*}
-%destructor term {sqlite3ExprDelete($$);}
-
-expr(A) ::= term(X). {A = X;}
-expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqlite3ExprSpan(A,&B,&E); }
-term(A) ::= NULL(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
-expr(A) ::= ID(X). {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
-expr(A) ::= JOIN_KW(X). {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
-expr(A) ::= nm(X) DOT nm(Y). {
- Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
- Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
- A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
-}
-expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
- Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
- Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
- Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Z);
- Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
- A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
-}
-term(A) ::= INTEGER|FLOAT|BLOB(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
-term(A) ::= STRING(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
-expr(A) ::= REGISTER(X). {A = sqlite3RegisterExpr(pParse, &X);}
-expr(A) ::= VARIABLE(X). {
- Token *pToken = &X;
- Expr *pExpr = A = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, pToken);
- sqlite3ExprAssignVarNumber(pParse, pExpr);
-}
-expr(A) ::= expr(E) COLLATE ids(C). {
- A = sqlite3ExprSetColl(pParse, E, &C);
-}
-%ifndef SQLITE_OMIT_CAST
-expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
- A = sqlite3PExpr(pParse, TK_CAST, E, 0, &T);
- sqlite3ExprSpan(A,&X,&Y);
-}
-%endif SQLITE_OMIT_CAST
-expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
- if( Y && Y->nExpr>SQLITE_MAX_FUNCTION_ARG ){
- sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
- }
- A = sqlite3ExprFunction(pParse, Y, &X);
- sqlite3ExprSpan(A,&X,&E);
- if( D && A ){
- A->flags |= EP_Distinct;
- }
-}
-expr(A) ::= ID(X) LP STAR RP(E). {
- A = sqlite3ExprFunction(pParse, 0, &X);
- sqlite3ExprSpan(A,&X,&E);
-}
-term(A) ::= CTIME_KW(OP). {
- /* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
- ** treated as functions that return constants */
- A = sqlite3ExprFunction(pParse, 0,&OP);
- if( A ){
- A->op = TK_CONST_FUNC;
- A->span = OP;
- }
-}
-expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
-expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
-expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y).
- {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
-expr(A) ::= expr(X) EQ|NE(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
-expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
- {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
-expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y).{A = sqlite3PExpr(pParse,@OP,X,Y,0);}
-expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y).
- {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
-expr(A) ::= expr(X) CONCAT(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
-%type likeop {struct LikeOp}
-likeop(A) ::= LIKE_KW(X). {A.eOperator = X; A.not = 0;}
-likeop(A) ::= NOT LIKE_KW(X). {A.eOperator = X; A.not = 1;}
-likeop(A) ::= MATCH(X). {A.eOperator = X; A.not = 0;}
-likeop(A) ::= NOT MATCH(X). {A.eOperator = X; A.not = 1;}
-%type escape {Expr*}
-%destructor escape {sqlite3ExprDelete($$);}
-escape(X) ::= ESCAPE expr(A). [ESCAPE] {X = A;}
-escape(X) ::= . [ESCAPE] {X = 0;}
-expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E). [LIKE_KW] {
- ExprList *pList;
- pList = sqlite3ExprListAppend(pParse,0, Y, 0);
- pList = sqlite3ExprListAppend(pParse,pList, X, 0);
- if( E ){
- pList = sqlite3ExprListAppend(pParse,pList, E, 0);
- }
- A = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
- if( OP.not ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
- sqlite3ExprSpan(A, &X->span, &Y->span);
- if( A ) A->flags |= EP_InfixFunc;
-}
-
-expr(A) ::= expr(X) ISNULL|NOTNULL(E). {
- A = sqlite3PExpr(pParse, @E, X, 0, 0);
- sqlite3ExprSpan(A,&X->span,&E);
-}
-expr(A) ::= expr(X) IS NULL(E). {
- A = sqlite3PExpr(pParse, TK_ISNULL, X, 0, 0);
- sqlite3ExprSpan(A,&X->span,&E);
-}
-expr(A) ::= expr(X) NOT NULL(E). {
- A = sqlite3PExpr(pParse, TK_NOTNULL, X, 0, 0);
- sqlite3ExprSpan(A,&X->span,&E);
-}
-expr(A) ::= expr(X) IS NOT NULL(E). {
- A = sqlite3PExpr(pParse, TK_NOTNULL, X, 0, 0);
- sqlite3ExprSpan(A,&X->span,&E);
-}
-expr(A) ::= NOT(B) expr(X). {
- A = sqlite3PExpr(pParse, @B, X, 0, 0);
- sqlite3ExprSpan(A,&B,&X->span);
-}
-expr(A) ::= BITNOT(B) expr(X). {
- A = sqlite3PExpr(pParse, @B, X, 0, 0);
- sqlite3ExprSpan(A,&B,&X->span);
-}
-expr(A) ::= MINUS(B) expr(X). [UMINUS] {
- A = sqlite3PExpr(pParse, TK_UMINUS, X, 0, 0);
- sqlite3ExprSpan(A,&B,&X->span);
-}
-expr(A) ::= PLUS(B) expr(X). [UPLUS] {
- A = sqlite3PExpr(pParse, TK_UPLUS, X, 0, 0);
- sqlite3ExprSpan(A,&B,&X->span);
-}
-%type between_op {int}
-between_op(A) ::= BETWEEN. {A = 0;}
-between_op(A) ::= NOT BETWEEN. {A = 1;}
-expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
- ExprList *pList = sqlite3ExprListAppend(pParse,0, X, 0);
- pList = sqlite3ExprListAppend(pParse,pList, Y, 0);
- A = sqlite3PExpr(pParse, TK_BETWEEN, W, 0, 0);
- if( A ){
- A->pList = pList;
- }else{
- sqlite3ExprListDelete(pList);
- }
- if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
- sqlite3ExprSpan(A,&W->span,&Y->span);
-}
-%ifndef SQLITE_OMIT_SUBQUERY
- %type in_op {int}
- in_op(A) ::= IN. {A = 0;}
- in_op(A) ::= NOT IN. {A = 1;}
- expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
- A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
- if( A ){
- A->pList = Y;
- sqlite3ExprSetHeight(A);
- }else{
- sqlite3ExprListDelete(Y);
- }
- if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
- sqlite3ExprSpan(A,&X->span,&E);
- }
- expr(A) ::= LP(B) select(X) RP(E). {
- A = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
- if( A ){
- A->pSelect = X;
- sqlite3ExprSetHeight(A);
- }else{
- sqlite3SelectDelete(X);
- }
- sqlite3ExprSpan(A,&B,&E);
- }
- expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
- A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
- if( A ){
- A->pSelect = Y;
- sqlite3ExprSetHeight(A);
- }else{
- sqlite3SelectDelete(Y);
- }
- if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
- sqlite3ExprSpan(A,&X->span,&E);
- }
- expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
- SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
- A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
- if( A ){
- A->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
- sqlite3ExprSetHeight(A);
- }else{
- sqlite3SrcListDelete(pSrc);
- }
- if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
- sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
- }
- expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
- Expr *p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
- if( p ){
- p->pSelect = Y;
- sqlite3ExprSpan(p,&B,&E);
- sqlite3ExprSetHeight(A);
- }else{
- sqlite3SelectDelete(Y);
- }
- }
-%endif SQLITE_OMIT_SUBQUERY
-
-/* CASE expressions */
-expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
- A = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
- if( A ){
- A->pList = Y;
- sqlite3ExprSetHeight(A);
- }else{
- sqlite3ExprListDelete(Y);
- }
- sqlite3ExprSpan(A, &C, &E);
-}
-%type case_exprlist {ExprList*}
-%destructor case_exprlist {sqlite3ExprListDelete($$);}
-case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
- A = sqlite3ExprListAppend(pParse,X, Y, 0);
- A = sqlite3ExprListAppend(pParse,A, Z, 0);
-}
-case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
- A = sqlite3ExprListAppend(pParse,0, Y, 0);
- A = sqlite3ExprListAppend(pParse,A, Z, 0);
-}
-%type case_else {Expr*}
-%destructor case_else {sqlite3ExprDelete($$);}
-case_else(A) ::= ELSE expr(X). {A = X;}
-case_else(A) ::= . {A = 0;}
-%type case_operand {Expr*}
-%destructor case_operand {sqlite3ExprDelete($$);}
-case_operand(A) ::= expr(X). {A = X;}
-case_operand(A) ::= . {A = 0;}
-
-%type exprlist {ExprList*}
-%destructor exprlist {sqlite3ExprListDelete($$);}
-%type nexprlist {ExprList*}
-%destructor nexprlist {sqlite3ExprListDelete($$);}
-
-exprlist(A) ::= nexprlist(X). {A = X;}
-exprlist(A) ::= . {A = 0;}
-nexprlist(A) ::= nexprlist(X) COMMA expr(Y).
- {A = sqlite3ExprListAppend(pParse,X,Y,0);}
-nexprlist(A) ::= expr(Y).
- {A = sqlite3ExprListAppend(pParse,0,Y,0);}
-
-
-///////////////////////////// The CREATE INDEX command ///////////////////////
-//
-cmd ::= CREATE(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
- ON nm(Y) LP idxlist(Z) RP(E). {
- sqlite3CreateIndex(pParse, &X, &D,
- sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
- &S, &E, SQLITE_SO_ASC, NE);
-}
-
-%type uniqueflag {int}
-uniqueflag(A) ::= UNIQUE. {A = OE_Abort;}
-uniqueflag(A) ::= . {A = OE_None;}
-
-%type idxlist {ExprList*}
-%destructor idxlist {sqlite3ExprListDelete($$);}
-%type idxlist_opt {ExprList*}
-%destructor idxlist_opt {sqlite3ExprListDelete($$);}
-%type idxitem {Token}
-
-idxlist_opt(A) ::= . {A = 0;}
-idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
-idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder(Z). {
- Expr *p = 0;
- if( C.n>0 ){
- p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
- sqlite3ExprSetColl(pParse, p, &C);
- }
- A = sqlite3ExprListAppend(pParse,X, p, &Y);
- sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
- if( A ) A->a[A->nExpr-1].sortOrder = Z;
-}
-idxlist(A) ::= idxitem(Y) collate(C) sortorder(Z). {
- Expr *p = 0;
- if( C.n>0 ){
- p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
- sqlite3ExprSetColl(pParse, p, &C);
- }
- A = sqlite3ExprListAppend(pParse,0, p, &Y);
- sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
- if( A ) A->a[A->nExpr-1].sortOrder = Z;
-}
-idxitem(A) ::= nm(X). {A = X;}
-
-%type collate {Token}
-collate(C) ::= . {C.z = 0; C.n = 0;}
-collate(C) ::= COLLATE ids(X). {C = X;}
-
-
-///////////////////////////// The DROP INDEX command /////////////////////////
-//
-cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
-
-///////////////////////////// The VACUUM command /////////////////////////////
-//
-%ifndef SQLITE_OMIT_VACUUM
-%ifndef SQLITE_OMIT_ATTACH
-cmd ::= VACUUM. {sqlite3Vacuum(pParse);}
-cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
-%endif SQLITE_OMIT_ATTACH
-%endif SQLITE_OMIT_VACUUM
-
-///////////////////////////// The PRAGMA command /////////////////////////////
-//
-%ifndef SQLITE_OMIT_PRAGMA
-cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
-cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
-cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
- sqlite3Pragma(pParse,&X,&Z,&Y,1);
-}
-cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
-cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
-nmnum(A) ::= plus_num(X). {A = X;}
-nmnum(A) ::= nm(X). {A = X;}
-%endif SQLITE_OMIT_PRAGMA
-plus_num(A) ::= plus_opt number(X). {A = X;}
-minus_num(A) ::= MINUS number(X). {A = X;}
-number(A) ::= INTEGER|FLOAT(X). {A = X;}
-plus_opt ::= PLUS.
-plus_opt ::= .
-
-//////////////////////////// The CREATE TRIGGER command /////////////////////
-
-%ifndef SQLITE_OMIT_TRIGGER
-
-cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
- Token all;
- all.z = A.z;
- all.n = (Z.z - A.z) + Z.n;
- sqlite3FinishTrigger(pParse, S, &all);
-}
-
-trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z)
- trigger_time(C) trigger_event(D)
- ON fullname(E) foreach_clause when_clause(G). {
- sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR);
- A = (Z.n==0?B:Z);
-}
-
-%type trigger_time {int}
-trigger_time(A) ::= BEFORE. { A = TK_BEFORE; }
-trigger_time(A) ::= AFTER. { A = TK_AFTER; }
-trigger_time(A) ::= INSTEAD OF. { A = TK_INSTEAD;}
-trigger_time(A) ::= . { A = TK_BEFORE; }
-
-%type trigger_event {struct TrigEvent}
-%destructor trigger_event {sqlite3IdListDelete($$.b);}
-trigger_event(A) ::= DELETE|INSERT(OP). {A.a = @OP; A.b = 0;}
-trigger_event(A) ::= UPDATE(OP). {A.a = @OP; A.b = 0;}
-trigger_event(A) ::= UPDATE OF inscollist(X). {A.a = TK_UPDATE; A.b = X;}
-
-foreach_clause ::= .
-foreach_clause ::= FOR EACH ROW.
-
-%type when_clause {Expr*}
-%destructor when_clause {sqlite3ExprDelete($$);}
-when_clause(A) ::= . { A = 0; }
-when_clause(A) ::= WHEN expr(X). { A = X; }
-
-%type trigger_cmd_list {TriggerStep*}
-%destructor trigger_cmd_list {sqlite3DeleteTriggerStep($$);}
-trigger_cmd_list(A) ::= trigger_cmd_list(Y) trigger_cmd(X) SEMI. {
- if( Y ){
- Y->pLast->pNext = X;
- }else{
- Y = X;
- }
- Y->pLast = X;
- A = Y;
-}
-trigger_cmd_list(A) ::= . { A = 0; }
-
-%type trigger_cmd {TriggerStep*}
-%destructor trigger_cmd {sqlite3DeleteTriggerStep($$);}
-// UPDATE
-trigger_cmd(A) ::= UPDATE orconf(R) nm(X) SET setlist(Y) where_opt(Z).
- { A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); }
-
-// INSERT
-trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F)
- VALUES LP itemlist(Y) RP.
- {A = sqlite3TriggerInsertStep(pParse->db, &X, F, Y, 0, R);}
-
-trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) select(S).
- {A = sqlite3TriggerInsertStep(pParse->db, &X, F, 0, S, R);}
-
-// DELETE
-trigger_cmd(A) ::= DELETE FROM nm(X) where_opt(Y).
- {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
-
-// SELECT
-trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); }
-
-// The special RAISE expression that may occur in trigger programs
-expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
- A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
- if( A ){
- A->iColumn = OE_Ignore;
- sqlite3ExprSpan(A, &X, &Y);
- }
-}
-expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
- A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
- if( A ) {
- A->iColumn = T;
- sqlite3ExprSpan(A, &X, &Y);
- }
-}
-%endif !SQLITE_OMIT_TRIGGER
-
-%type raisetype {int}
-raisetype(A) ::= ROLLBACK. {A = OE_Rollback;}
-raisetype(A) ::= ABORT. {A = OE_Abort;}
-raisetype(A) ::= FAIL. {A = OE_Fail;}
-
-
-//////////////////////// DROP TRIGGER statement //////////////////////////////
-%ifndef SQLITE_OMIT_TRIGGER
-cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
- sqlite3DropTrigger(pParse,X,NOERR);
-}
-%endif !SQLITE_OMIT_TRIGGER
-
-//////////////////////// ATTACH DATABASE file AS name /////////////////////////
-%ifndef SQLITE_OMIT_ATTACH
-cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
- sqlite3Attach(pParse, F, D, K);
-}
-cmd ::= DETACH database_kw_opt expr(D). {
- sqlite3Detach(pParse, D);
-}
-
-%type key_opt {Expr*}
-%destructor key_opt {sqlite3ExprDelete($$);}
-key_opt(A) ::= . { A = 0; }
-key_opt(A) ::= KEY expr(X). { A = X; }
-
-database_kw_opt ::= DATABASE.
-database_kw_opt ::= .
-%endif SQLITE_OMIT_ATTACH
-
-////////////////////////// REINDEX collation //////////////////////////////////
-%ifndef SQLITE_OMIT_REINDEX
-cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);}
-cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);}
-%endif SQLITE_OMIT_REINDEX
-
-/////////////////////////////////// ANALYZE ///////////////////////////////////
-%ifndef SQLITE_OMIT_ANALYZE
-cmd ::= ANALYZE. {sqlite3Analyze(pParse, 0, 0);}
-cmd ::= ANALYZE nm(X) dbnm(Y). {sqlite3Analyze(pParse, &X, &Y);}
-%endif
-
-//////////////////////// ALTER TABLE table ... ////////////////////////////////
-%ifndef SQLITE_OMIT_ALTERTABLE
-cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). {
- sqlite3AlterRenameTable(pParse,X,&Z);
-}
-cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column(Y). {
- sqlite3AlterFinishAddColumn(pParse, &Y);
-}
-add_column_fullname ::= fullname(X). {
- sqlite3AlterBeginAddColumn(pParse, X);
-}
-kwcolumn_opt ::= .
-kwcolumn_opt ::= COLUMNKW.
-%endif SQLITE_OMIT_ALTERTABLE
-
-//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
-%ifndef SQLITE_OMIT_VIRTUALTABLE
-cmd ::= create_vtab. {sqlite3VtabFinishParse(pParse,0);}
-cmd ::= create_vtab LP vtabarglist RP(X). {sqlite3VtabFinishParse(pParse,&X);}
-create_vtab ::= CREATE VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). {
- sqlite3VtabBeginParse(pParse, &X, &Y, &Z);
-}
-vtabarglist ::= vtabarg.
-vtabarglist ::= vtabarglist COMMA vtabarg.
-vtabarg ::= . {sqlite3VtabArgInit(pParse);}
-vtabarg ::= vtabarg vtabargtoken.
-vtabargtoken ::= ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
-vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);}
-lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);}
-anylist ::= .
-anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
-%endif SQLITE_OMIT_VIRTUALTABLE
Index: MultiSource/Applications/lemon/wireshark_COPYING
===================================================================
--- MultiSource/Applications/lemon/wireshark_COPYING
+++ /dev/null
@@ -1,378 +0,0 @@
-This text consists of two parts:
-
-Part I: Some remarks regarding the license given in
-Part II: The actual license that covers Wireshark.
-
-When in doubt: Part II is the legally binding part, Part I is just
-there to make it easier for people that are not familiar with the
-GPLv2.
-
-
-------------------------------------------------------------------------
-Part I:
-
-Wireshark is distributed under the GNU GPLv2. There are no restrictions
-on its use. There are restrictions on its distribution in source or
-binary form.
-
-Most parts of Wireshark are covered by a "GPL version 2 or later" license.
-Some files are covered by different licenses that are compatible with
-the GPLv2.
-
-As a notable exception the pidl utility at tools/pidl is covered by a
-"GPL version 3 or later" license. Note that only the tool itself
-is covered by this license, not the source code generated by it. The
-pidl authors do not consider generated code a derived work of pidl.
-
-Parts of Wireshark can be built and distributed as libraries. These
-parts are still covered by the GPL, and NOT by the Lesser General Public
-License or any other license.
-
-If you integrate all or part of Wireshark into your own application, then
-that application must be released under a license compatible with the GPL.
-
-The full text of the GNU GPL follows.
-
-------------------------------------------------------------------------
-Part II:
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C) 19yy
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
Index: MultiSource/Applications/lemon/wireshark_dtd_grammar.lemon
===================================================================
--- MultiSource/Applications/lemon/wireshark_dtd_grammar.lemon
+++ /dev/null
@@ -1,217 +0,0 @@
-%include {
-
-/* dtd_parser.lemon
-* XML dissector for wireshark
-* XML's DTD grammar
-*
-* Copyright 2005, Luis E. Garcia Ontanon
-*
-* $Id: dtd_grammar.lemon 20443 2007-01-15 20:14:00Z lego $
-*
-* Wireshark - Network traffic analyzer
-* By Gerald Combs
-* Copyright 1998 Gerald Combs
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 2
-* of the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-#include
-#include
-#include "dtd.h"
-#include "dtd_parse.h"
-
-static dtd_named_list_t* dtd_named_list_new(gchar* name, GPtrArray* list) {
- dtd_named_list_t* nl = g_malloc(sizeof(dtd_named_list_t));
-
- nl->name = name;
- nl->list = list;
-
- return nl;
-}
-
-static GPtrArray* g_ptr_array_join(GPtrArray* a, GPtrArray* b){
-
- while(b->len > 0) {
- g_ptr_array_add(a,g_ptr_array_remove_index_fast(b,0));
- }
-
- g_ptr_array_free(b,TRUE);
-
- return a;
-}
-
-}
-
-%name DtdParse
-
-%extra_argument { dtd_build_data_t *bd }
-
-%token_destructor {
- if ($$) {
- if ($$->text) g_free($$->text);
- if ($$->location) g_free($$->location);
- g_free($$);
- }
-}
-
-%syntax_error {
- if (!TOKEN)
- g_string_sprintfa(bd->error,"syntax error at end of file");
- else
- g_string_sprintfa(bd->error,"syntax error in %s at or before '%s': \n", TOKEN->location,TOKEN->text);
-}
-
-%parse_failure {
- g_string_sprintfa(bd->error,"DTD parsing failure\n");
-}
-
-%token_prefix TOKEN_
-
-%token_type { dtd_token_data_t* }
-
-dtd ::= doctype.
-dtd ::= dtd_parts.
-
-doctype ::= TAG_START DOCTYPE_KW NAME(Name) OPEN_BRACKET dtd_parts CLOSE_BRACKET TAG_STOP. {
- dtd_named_list_t* root;
- GPtrArray* root_elems = g_ptr_array_new();
- guint i;
-
- if(! bd->proto_name) {
- bd->proto_name = Name->text;
- }
-
- if(bd->proto_root)
- g_free(bd->proto_root);
-
- bd->proto_root = Name->text;
-
- g_strdown(bd->proto_name);
-
- for( i = 0; i< bd->elements->len; i++) {
- dtd_named_list_t* el = g_ptr_array_index(bd->elements,i);
-
- g_ptr_array_add(root_elems,g_strdup(el->name));
- }
-
- root = dtd_named_list_new(g_strdup(Name->text),root_elems);
-
- g_ptr_array_add(bd->elements,root);
-
- g_free(Name->location);
- g_free(Name);
-
-}
-
-dtd_parts ::= dtd_parts element(Element). { g_ptr_array_add(bd->elements,Element); }
-dtd_parts ::= dtd_parts attlist(Attlist). { g_ptr_array_add(bd->attributes,Attlist); }
-dtd_parts ::= element(Element). { g_ptr_array_add(bd->elements,Element); }
-dtd_parts ::= attlist(Attlist). { g_ptr_array_add(bd->attributes,Attlist); }
-
-%type attlist { dtd_named_list_t* }
-attlist(A) ::= TAG_START ATTLIST_KW NAME(B) attrib_list(TheList) TAG_STOP. {
- g_strdown(B->text);
- A = dtd_named_list_new(B->text,TheList);
- g_free(B->location);
- g_free(B);
-}
-
-%type element { dtd_named_list_t* }
-element(A) ::= TAG_START ELEMENT_KW NAME(B) sub_elements(C) TAG_STOP. {
- g_strdown(B->text);
- A = dtd_named_list_new(B->text,C);
- g_free(B->location);
- g_free(B);
-}
-
-%type attrib_list { GPtrArray* }
-attrib_list(A) ::= attrib_list(B) attrib(C). { g_ptr_array_add(B,C); A = B; }
-attrib_list(A) ::= attrib(B). { A = g_ptr_array_new(); g_ptr_array_add(A,B); }
-
-%type attrib { gchar* }
-attrib(A) ::= NAME(B) att_type att_default. {
- A = B->text;
- g_strdown(A);
- g_free(B->location);
- g_free(B);
-}
-
-att_type ::= ATT_TYPE.
-att_type ::= enumeration.
-
-att_default ::= ATT_DEF.
-att_default ::= ATT_DEF_WITH_VALUE QUOTED.
-att_default ::= QUOTED.
-att_default ::= IMPLIED_KW.
-att_default ::= REQUIRED_KW.
-
-enumeration ::= OPEN_PARENS enum_list CLOSE_PARENS.
-
-enum_list ::= enum_list PIPE enum_item.
-enum_list ::= enum_item.
-enum_list ::= enumeration.
-enum_list ::= enum_list PIPE enumeration.
-
-enum_item ::= NAME.
-enum_item ::= QUOTED.
-
-
-%type sub_elements { GPtrArray* }
-sub_elements(A) ::= sub_elements(B) STAR. {A=B;}
-sub_elements(A) ::= sub_elements(B) PLUS. {A=B;}
-sub_elements(A) ::= sub_elements(B) QUESTION. {A=B;}
-sub_elements(A) ::= OPEN_PARENS ELEM_DATA CLOSE_PARENS. { A = g_ptr_array_new(); }
-sub_elements(A) ::= OPEN_PARENS element_list(B) COMMA ELEM_DATA CLOSE_PARENS. { A = B; }
-sub_elements(A) ::= OPEN_PARENS element_list(B) PIPE ELEM_DATA CLOSE_PARENS. { A = B; }
-sub_elements(A) ::= OPEN_PARENS element_list(B) CLOSE_PARENS. { A = B; }
-sub_elements(A) ::= EMPTY_KW. { A = g_ptr_array_new(); }
-
-%type element_list { GPtrArray* }
-element_list(A) ::= element_list(B) COMMA element_child(C). { g_ptr_array_add(B,C); A = B; }
-element_list(A) ::= element_list(B) PIPE element_child(C). { g_ptr_array_add(B,C); A = B; }
-element_list(A) ::= element_child(B). { A = g_ptr_array_new(); g_ptr_array_add(A,B); }
-element_list(A) ::= sub_elements(B). { A = B; }
-element_list(A) ::= element_list(B) COMMA sub_elements(C). { A = g_ptr_array_join(B,C); }
-element_list(A) ::= element_list(B) PIPE sub_elements(C). { A = g_ptr_array_join(B,C); }
-
-%type element_child { gchar* }
-element_child(A) ::= NAME(B). {
- A = B->text;
- g_strdown(A);
- g_free(B->location);
- g_free(B);
-}
-
-element_child(A) ::= NAME(B) STAR. {
- A = B->text;
- g_strdown(A);
- g_free(B->location);
- g_free(B);
-}
-
-element_child(A) ::= NAME(B) QUESTION. {
- A = B->text;
- g_strdown(A);
- g_free(B->location);
- g_free(B);
-}
-
-element_child(A) ::= NAME(B) PLUS. {
- A = B->text;
- g_strdown(A);
- g_free(B->location);
- g_free(B);
-}
-
Index: MultiSource/Applications/lemon/wireshark_grammar.lemon
===================================================================
--- MultiSource/Applications/lemon/wireshark_grammar.lemon
+++ /dev/null
@@ -1,294 +0,0 @@
-/* $Id: grammar.lemon 21321 2007-04-03 19:08:00Z lego $ */
-
-%include {
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "dfilter-int.h"
-#include "syntax-tree.h"
-#include "sttype-range.h"
-#include "sttype-test.h"
-#include "sttype-function.h"
-#include "drange.h"
-
-#include "grammar.h"
-
-#ifdef _WIN32
-#pragma warning(disable:4671)
-#endif
-
-/* End of C code */
-}
-
-/* Parser Information */
-%name Dfilter
-%token_prefix TOKEN_
-%extra_argument {dfwork_t *dfw}
-
-/* Terminal and Non-Terminal types and destructors */
-%token_type {stnode_t*}
-%token_destructor {stnode_free($$);}
-
-%type sentence {stnode_t*}
-
-
-%type expr {stnode_t*}
-%destructor expr {stnode_free($$);}
-
-%type entity {stnode_t*}
-%destructor entity {stnode_free($$);}
-
-%type relation_test {stnode_t*}
-%destructor relation_test {stnode_free($$);}
-
-%type logical_test {stnode_t*}
-%destructor logical_test {stnode_free($$);}
-
-%type rel_op2 {test_op_t}
-
-%type range {stnode_t*}
-%destructor range {stnode_free($$);}
-
-%type drnode {drange_node*}
-%destructor drnode {drange_node_free($$);}
-
-%type drnode_list {GSList*}
-%destructor drnode_list {drange_node_free_list($$);}
-
-%type funcparams {GSList*}
-%destructor funcparams {st_funcparams_free($$);}
-
-/* This is called as soon as a syntax error happens. After that,
-any "error" symbols are shifted, if possible. */
-%syntax_error {
-
- header_field_info *hfinfo;
-
- if (!TOKEN) {
- dfilter_fail("Unexpected end of filter string.");
- return;
- }
-
- switch(stnode_type_id(TOKEN)) {
- case STTYPE_UNINITIALIZED:
- dfilter_fail("Syntax error.");
- break;
- case STTYPE_TEST:
- dfilter_fail("Syntax error, TEST.");
- break;
- case STTYPE_STRING:
- dfilter_fail("The string \"%s\" was unexpected in this context.",
- stnode_data(TOKEN));
- break;
- case STTYPE_UNPARSED:
- dfilter_fail("\"%s\" was unexpected in this context.",
- stnode_data(TOKEN));
- break;
- case STTYPE_INTEGER:
- dfilter_fail("The integer %d was unexpected in this context.",
- stnode_value(TOKEN));
- break;
- case STTYPE_FIELD:
- hfinfo = stnode_data(TOKEN);
- dfilter_fail("Syntax error near \"%s\".", hfinfo->abbrev);
- break;
- case STTYPE_FUNCTION:
- dfilter_fail("The function s was unexpected in this context.");
- break;
-
- /* These aren't handed to use as terminal tokens from
- the scanner, so was can assert that we'll never
- see them here. */
- case STTYPE_NUM_TYPES:
- case STTYPE_RANGE:
- case STTYPE_FVALUE:
- g_assert_not_reached();
- break;
- }
-}
-
-/* When a parse fails, mark an error. This occurs after
-the above syntax_error code and after the parser fails to
-use error recovery, shifting an "error" symbol and successfully
-shifting 3 more symbols. */
-%parse_failure {
- dfw->syntax_error = TRUE;
-}
-
-/* ----------------- The grammar -------------- */
-
-/* Associativity */
-%left TEST_AND.
-%left TEST_OR.
-%nonassoc TEST_EQ TEST_NE TEST_LT TEST_LE TEST_GT TEST_GE TEST_CONTAINS TEST_MATCHES TEST_BITWISE_AND.
-%right TEST_NOT.
-
-/* Top-level targets */
-sentence ::= expr(X). { dfw->st_root = X; }
-sentence ::= . { dfw->st_root = NULL; }
-
-expr(X) ::= relation_test(R). { X = R; }
-expr(X) ::= logical_test(L). { X = L; }
-
-
-/* Logical tests */
-logical_test(T) ::= expr(E) TEST_AND expr(F).
-{
- T = stnode_new(STTYPE_TEST, NULL);
- sttype_test_set2(T, TEST_OP_AND, E, F);
-}
-
-logical_test(T) ::= expr(E) TEST_OR expr(F).
-{
- T = stnode_new(STTYPE_TEST, NULL);
- sttype_test_set2(T, TEST_OP_OR, E, F);
-}
-
-logical_test(T) ::= TEST_NOT expr(E).
-{
- T = stnode_new(STTYPE_TEST, NULL);
- sttype_test_set1(T, TEST_OP_NOT, E);
-}
-
-logical_test(T) ::= entity(E).
-{
- T = stnode_new(STTYPE_TEST, NULL);
- sttype_test_set1(T, TEST_OP_EXISTS, E);
-}
-
-
-
-/* Entities, or things that can be compared/tested/checked */
-entity(E) ::= FIELD(F). { E = F; }
-entity(E) ::= STRING(S). { E = S; }
-entity(E) ::= UNPARSED(U). { E = U; }
-entity(E) ::= range(R). { E = R; }
-
-
-/* Ranges */
-range(R) ::= FIELD(F) LBRACKET drnode_list(L) RBRACKET.
-{
- R = stnode_new(STTYPE_RANGE, NULL);
- sttype_range_set(R, F, L);
-
- /* Delete the list, but not the drange_nodes that
- * the list contains. */
- g_slist_free(L);
-}
-
-drnode_list(L) ::= drnode(D).
-{
- L = g_slist_append(NULL, D);
-}
-
-drnode_list(L) ::= drnode_list(P) COMMA drnode(D).
-{
- L = g_slist_append(P, D);
-}
-
-/* x:y is offset:length */
-drnode(D) ::= INTEGER(X) COLON INTEGER(Y).
-{
- D = drange_node_new();
- drange_node_set_start_offset(D, stnode_value(X));
- drange_node_set_length(D, stnode_value(Y));
-
- stnode_free(X);
- stnode_free(Y);
-}
-
-/* x-y == offset:offset */
-drnode(D) ::= INTEGER(X) HYPHEN INTEGER(Y).
-{
- D = drange_node_new();
- drange_node_set_start_offset(D, stnode_value(X));
- drange_node_set_end_offset(D, stnode_value(Y));
-
- stnode_free(X);
- stnode_free(Y);
-}
-
-
-/* :y == from start to offset */
-drnode(D) ::= COLON INTEGER(Y).
-{
- D = drange_node_new();
- drange_node_set_start_offset(D, 0);
- drange_node_set_length(D, stnode_value(Y));
-
- stnode_free(Y);
-}
-
-/* x: from offset to end */
-drnode(D) ::= INTEGER(X) COLON.
-{
- D = drange_node_new();
- drange_node_set_start_offset(D, stnode_value(X));
- drange_node_set_to_the_end(D);
-
- stnode_free(X);
-}
-
-/* x == x:1 */
-drnode(D) ::= INTEGER(X).
-{
- D = drange_node_new();
- drange_node_set_start_offset(D, stnode_value(X));
- drange_node_set_length(D, 1);
-
- stnode_free(X);
-}
-
-
-
-/* Relational tests */
-relation_test(T) ::= entity(E) rel_op2(O) entity(F).
-{
- T = stnode_new(STTYPE_TEST, NULL);
- sttype_test_set2(T, O, E, F);
-}
-
-rel_op2(O) ::= TEST_EQ. { O = TEST_OP_EQ; }
-rel_op2(O) ::= TEST_NE. { O = TEST_OP_NE; }
-rel_op2(O) ::= TEST_GT. { O = TEST_OP_GT; }
-rel_op2(O) ::= TEST_GE. { O = TEST_OP_GE; }
-rel_op2(O) ::= TEST_LT. { O = TEST_OP_LT; }
-rel_op2(O) ::= TEST_LE. { O = TEST_OP_LE; }
-rel_op2(O) ::= TEST_BITWISE_AND. { O = TEST_OP_BITWISE_AND; }
-rel_op2(O) ::= TEST_CONTAINS. { O = TEST_OP_CONTAINS; }
-rel_op2(O) ::= TEST_MATCHES. { O = TEST_OP_MATCHES; }
-
-
-/* Functions */
-
-/* A function can have one or more parameters */
-entity(E) ::= FUNCTION(F) LPAREN funcparams(P) RPAREN.
-{
- E = F;
- sttype_function_set_params(E, P);
-}
-
-/* A function can have zero parameters. */
-entity(E) ::= FUNCTION(F) LPAREN RPAREN.
-{
- E = F;
-}
-
-funcparams(P) ::= entity(E).
-{
- P = g_slist_append(NULL, E);
-}
-
-funcparams(P) ::= funcparams(L) COMMA entity(E).
-{
- P = g_slist_append(L, E);
-}
-
-
-/* Any expression inside parens is simply that expression */
-expr(X) ::= LPAREN expr(Y) RPAREN.
-{
- X = Y;
-}
-
Index: MultiSource/Applications/lemon/wireshark_mate_grammar.lemon
===================================================================
--- MultiSource/Applications/lemon/wireshark_mate_grammar.lemon
+++ /dev/null
@@ -1,719 +0,0 @@
-%include {
-
-/* mate_grammar.lemon
-* MATE's configuration language grammar
-*
-* Copyright 2005, Luis E. Garcia Ontanon
-*
-* $Id: mate_grammar.lemon 23221 2007-10-17 21:25:16Z morriss $
-*
-* Wireshark - Network traffic analyzer
-* By Gerald Combs
-* Copyright 1998 Gerald Combs
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 2
-* of the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-#include "mate.h"
-#include "mate_grammar.h"
-#include
-#include
-
-#define DUMMY void*
-
-typedef struct _extraction {
- gchar* as;
- header_field_info* hfi;
- struct _extraction* next;
- struct _extraction* last;
-} extraction_t;
-
-typedef struct _pdu_criteria_t {
- AVPL* criterium_avpl;
- avpl_match_mode criterium_match_mode;
- accept_mode_t criterium_accept_mode;
-} pdu_criteria_t;
-
-typedef struct _gop_options {
- gop_tree_mode_t pdu_tree_mode;
- gboolean drop_unassigned;
- gboolean show_times;
- float expiration;
- float idle_timeout;
- float lifetime;
- AVPL* start;
- AVPL* stop;
- AVPL* extras;
-} gop_options_t;
-
-typedef struct _gog_statements {
- float expiration;
- gop_tree_mode_t gop_tree_mode;
- GPtrArray* transform_list;
- AVPL* extras;
- LoAL* current_gogkeys;
-} gog_statement_t;
-
-typedef struct _transf_match_t {
- avpl_match_mode match_mode;
- AVPL* avpl;
-} transf_match_t;
-
-typedef struct _transf_action_t {
- avpl_replace_mode replace_mode;
- AVPL* avpl;
-} transf_action_t;
-
-static void configuration_error(mate_config* mc, const gchar* fmt, ...) {
- static gchar error_buffer[256];
- const gchar* incl;
- gint i;
- mate_config_frame* current_frame;
- va_list list;
-
- va_start( list, fmt );
- g_vsnprintf(error_buffer,sizeof(error_buffer),fmt,list);
- va_end( list );
-
- i = (gint) mc->config_stack->len;
-
- while (i--) {
-
- if (i>0) {
- incl = "\n included from: ";
- } else {
- incl = " ";
- }
-
- current_frame = g_ptr_array_index(mc->config_stack,(guint)i);
-
- g_string_sprintfa(mc->config_error,"%s%s at line %u",incl, current_frame->filename, current_frame->linenum);
- }
-
- g_string_sprintfa(mc->config_error,": %s\n",error_buffer);
-
- THROW(MateConfigError);
-
-}
-
-static AVPL_Transf* new_transform_elem(AVPL* match, AVPL* replace, avpl_match_mode match_mode, avpl_replace_mode replace_mode) {
- AVPL_Transf* t = g_malloc(sizeof(AVPL_Transf));
-
- t->name = NULL;
- t->match = match;
- t->replace = replace;
- t->match_mode = match_mode;
- t->replace_mode = replace_mode;
-
- t->map = NULL;
- t->next = NULL;
-
- return t;
-}
-
-static gchar* recolonize(mate_config* mc, gchar* s) {
- GString* str = g_string_new("");
- gchar** vec;
- gchar* r;
- guint i,v;
- gchar c;
-
- vec = g_strsplit(s,":",0);
-
- for (i = 0; vec[i]; i++) {
- g_strdown(vec[i]);
-
- v = 0;
- switch ( strlen(vec[i]) ) {
- case 2:
- c = vec[i][1];
- vec[i][1] = vec[i][0];
- vec[i][0] = c;
- if (vec[i][0] >= '0' && vec[i][0] <= '9') {
- v += (vec[i][1] - '0' )*16;
- } else {
- v += (vec[i][1] - 'a' + 10)*16;
- }
- case 1:
- if (vec[i][0] >= '0' && vec[i][0] <= '9') {
- v += (vec[i][0] - '0' );
- } else {
- v += (vec[i][0] - 'a' + 10);
- }
- case 0:
- break;
- default:
- configuration_error(mc,"bad token %s",s);
- }
-
- g_string_sprintfa(str,":%.2X",v);
- }
-
- g_strfreev(vec);
-
- g_string_erase(str,0,1);
-
- r = str->str;
-
- g_string_free(str,FALSE);
-
- return r;
-}
-
-}
-
-%name MateParser
-
-%token_prefix TOKEN_
-
-%token_type { gchar* }
-%token_destructor { if ($$) g_free($$); }
-
-%extra_argument { mate_config* mc }
-
-%syntax_error {
- configuration_error(mc,"Syntax Error before %s",yyminor);
-}
-
-%parse_failure {
- configuration_error(mc,"Parse Error");
-}
-
-%type transform_decl { AVPL_Transf* }
-%type transform_body { AVPL_Transf* }
-%type transform_statements { AVPL_Transf* }
-%type transform_statement { AVPL_Transf* }
-%type transform_match { transf_match_t* }
-%type transform_action { transf_action_t* }
-%type match_mode { avpl_match_mode }
-%type action_mode { avpl_replace_mode }
-
-%type gop_name { gchar* }
-%type time_value { float }
-%type pdu_name { gchar* }
-%type gop_tree_mode { gop_tree_mode_t }
-%type true_false { gboolean }
-
-%type criteria_statement { pdu_criteria_t* }
-%type accept_mode { accept_mode_t }
-%type pdu_drop_unassigned_statement { gboolean }
-%type discard_pdu_data_statement { gboolean }
-%type last_extracted_statement { gboolean }
-
-%type extraction_statement {extraction_t*}
-%type extraction_statements {extraction_t*}
-
-%type gop_options { gop_options_t* }
-
-%type gop_start_statement { AVPL* }
-%type gop_stop_statement { AVPL* }
-%type extra_statement { AVPL* }
-%type gop_drop_unassigned_statement { gboolean }
-%type show_goptree_statement { gop_tree_mode_t }
-%type show_times_statement { gboolean }
-%type gop_expiration_statement { float }
-%type idle_timeout_statement { float }
-%type lifetime_statement { float }
-
-%type gog_statements { gog_statement_t* }
-%type gog_expiration_statement { float }
-%type gog_goptree_statement { gop_tree_mode_t }
-%type gog_key_statements { LoAL* }
-%type gog_key_statement { AVPL* }
-%type transform_list_statement { GPtrArray* }
-%type transform { AVPL_Transf* }
-%type gop_tree_type { gop_tree_mode_t }
-
-%type payload_statement { GPtrArray* }
-%type proto_stack { GPtrArray* }
-%type field { header_field_info* }
-%type transform_list { GPtrArray* }
-%type avpl { AVPL* }
-%type avps { AVPL* }
-%type avp { AVP* }
-%type value { gchar* }
-%type avp_oneoff { gchar* }
-
-
-mate_config ::= decls.
-
-decls ::= decls decl.
-decls ::= .
-
-decl ::= pdu_decl.
-decl ::= gop_decl.
-decl ::= gog_decl.
-decl ::= transform_decl.
-decl ::= defaults_decl.
-decl ::= debug_decl.
-decl ::= DONE_KW SEMICOLON.
-
-/************* DEBUG
-*/
-
-debug_decl ::= DEBUG_KW OPEN_BRACE dbgfile_default dbglevel_default pdu_dbglevel_default gop_dbglevel_default gog_dbglevel_default CLOSE_BRACE SEMICOLON.
-
-dbgfile_default ::= FILENAME_KW QUOTED(Filename) SEMICOLON. { mc->dbg_facility = eth_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); }
-dbgfile_default ::= FILENAME_KW NAME(Filename) SEMICOLON. { mc->dbg_facility = eth_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); }
-dbgfile_default ::= .
-
-dbglevel_default ::= LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_lvl = (int) strtol(LevelString,NULL,10); }
-dbglevel_default ::= .
-
-pdu_dbglevel_default ::= PDU_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_pdu_lvl = (int) strtol(LevelString,NULL,10); }
-pdu_dbglevel_default ::= .
-
-gop_dbglevel_default ::= GOP_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gop_lvl = (int) strtol(LevelString,NULL,10); }
-gop_dbglevel_default ::= .
-
-gog_dbglevel_default ::= GOG_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gog_lvl = (int) strtol(LevelString,NULL,10); }
-gog_dbglevel_default ::= .
-
-
-/************* DEFAULTS
-*/
-
-defaults_decl ::= DEFAULT_KW OPEN_BRACE pdu_defaults gop_defaults gog_defaults CLOSE_BRACE SEMICOLON.
-
-pdu_defaults ::= PDU_KW OPEN_BRACE pdu_last_extracted_default pdu_drop_unassigned_default pdu_discard_default CLOSE_BRACE SEMICOLON.
-pdu_defaults ::= .
-
-pdu_last_extracted_default ::= LAST_EXTRACTED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.last_extracted = Flag; }
-pdu_last_extracted_default ::= .
-
-pdu_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.drop_unassigned = Flag; }
-pdu_drop_unassigned_default ::= .
-
-pdu_discard_default ::= DISCARD_PDU_DATA_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.discard = Flag; }
-pdu_discard_default ::= .
-
-gop_defaults ::= GOP_KW OPEN_BRACE gop_expiration_default gop_idle_timeout_default gop_lifetime_default gop_drop_unassigned_default gop_tree_mode_default gop_show_times_default CLOSE_BRACE SEMICOLON.
-gop_defaults ::= .
-
-gop_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
-gop_expiration_default ::= .
-
-gop_idle_timeout_default ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { mc->defaults.gop.idle_timeout = B; }
-gop_idle_timeout_default ::= .
-
-gop_lifetime_default ::= LIFETIME_KW time_value(B) SEMICOLON. { mc->defaults.gop.lifetime = B; }
-gop_lifetime_default ::= .
-
-gop_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { mc->defaults.gop.drop_unassigned = B; }
-gop_drop_unassigned_default ::= .
-
-gop_tree_mode_default ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { mc->defaults.gop.pdu_tree_mode = B; }
-gop_tree_mode_default ::= .
-
-gop_show_times_default ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { mc->defaults.gop.show_times = B; }
-gop_show_times_default ::= .
-
-gog_defaults ::= GOG_KW OPEN_BRACE gog_expiration_default gop_tree_mode_default gog_goptree_default CLOSE_BRACE SEMICOLON.
-gog_defaults ::= .
-
-gog_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
-gog_expiration_default ::= .
-
-gog_goptree_default ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { mc->defaults.gog.gop_tree_mode = B; }
-gog_goptree_default ::= .
-
-
-/******************************************* TRANSFORM
-*/
-
-transform_decl(A) ::= TRANSFORM_KW NAME(B) transform_body(C) SEMICOLON. {
- AVPL_Transf* c;
-
- if ( g_hash_table_lookup(mc->transfs,B) ) {
- configuration_error(mc,"A transformation called '%s' exists already",B);
- }
-
- for ( c = C; c; c = c->next )
- c->name = g_strdup(B);
-
- g_hash_table_insert(mc->transfs,C->name,C);
-
- A = NULL;
-}
-
-transform_body(A) ::= OPEN_BRACE transform_statements(B) CLOSE_BRACE. { A = B; }
-
-transform_statements(A) ::= transform_statements(C) transform_statement(B). {
- AVPL_Transf* c;
-
- for ( c = C; c->next; c = c->next ) ;
- c->next = B;
- A = C;
-}
-
-transform_statements(A) ::= transform_statement(B). { A = B; }
-
-transform_statement(A) ::= transform_match(Match) transform_action(Action) SEMICOLON. {
- A = new_transform_elem(Match->avpl,Action->avpl,Match->match_mode,Action->replace_mode);
-}
-
-transform_match(A) ::= MATCH_KW match_mode(Mode) avpl(Avpl). {
- A = g_malloc(sizeof(transf_match_t));
- A->match_mode = Mode;
- A->avpl = Avpl;
-}
-
-transform_match(A) ::= . {
- A = g_malloc(sizeof(transf_match_t));
- A->match_mode = AVPL_STRICT;
- A->avpl = new_avpl("");
-
-}
-
-transform_action(A) ::= . {
- A = g_malloc(sizeof(transf_action_t));
- A->replace_mode = AVPL_INSERT;
- A->avpl = new_avpl("");
-}
-transform_action(A) ::= action_mode(Mode) avpl(Avpl). {
- A = g_malloc(sizeof(transf_action_t));
- A->replace_mode = Mode;
- A->avpl = Avpl;
-}
-
-match_mode(A) ::= . { A = AVPL_STRICT; }
-match_mode(A) ::= STRICT_KW. { A = AVPL_STRICT; }
-match_mode(A) ::= EVERY_KW. { A = AVPL_EVERY; }
-match_mode(A) ::= LOOSE_KW. { A = AVPL_LOOSE; }
-
-action_mode(A) ::= REPLACE_KW. { A = AVPL_REPLACE; }
-action_mode(A) ::= INSERT_KW. { A = AVPL_INSERT; }
-action_mode(A) ::= . { A = AVPL_INSERT; }
-
-/******************************************* PDU
-*/
-
-pdu_decl ::=
- PDU_KW NAME(Name) PROTO_KW field(Field) TRANSPORT_KW proto_stack(Stack)
- OPEN_BRACE
- payload_statement(Payload)
- extraction_statements(Extraction)
- transform_list_statement(Transform)
- criteria_statement(Criteria)
- pdu_drop_unassigned_statement(DropUnassigned)
- discard_pdu_data_statement(DistcardPduData)
- last_extracted_statement(LastExtracted)
- CLOSE_BRACE SEMICOLON.
-{
-
- mate_cfg_pdu* cfg = new_pducfg(Name);
- extraction_t *extraction, *next_extraction;
- GPtrArray* transport_stack = g_ptr_array_new();
- int i;
-
- if (! cfg ) configuration_error(mc,"could not create Pdu %s.",Name);
-
- cfg->hfid_proto = Field->id;
-
- cfg->last_extracted = LastExtracted;
- cfg->discard = DistcardPduData;
- cfg->drop_unassigned = DropUnassigned;
-
- g_string_sprintfa(mc->protos_filter,"||%s",Field->abbrev);
-
- /* flip the transport_stack */
- for (i = Stack->len - 1; Stack->len; i--) {
- g_ptr_array_add(transport_stack,g_ptr_array_remove_index(Stack,i));
- }
-
- g_ptr_array_free(Stack,FALSE);
-
- cfg->transport_ranges = transport_stack;
- cfg->payload_ranges = Payload;
-
- if (Criteria) {
- cfg->criterium = Criteria->criterium_avpl;
- cfg->criterium_match_mode = Criteria->criterium_match_mode;
- cfg->criterium_accept_mode = Criteria->criterium_accept_mode;
- }
-
- cfg->transforms = Transform;
-
- for (extraction = Extraction; extraction; extraction = next_extraction) {
- next_extraction = extraction->next;
-
- if ( ! add_hfid(extraction->hfi, extraction->as, cfg->hfids_attr) ) {
- configuration_error(mc,"MATE: failed to create extraction rule '%s'",extraction->as);
- }
-
- g_free(extraction);
- }
-}
-
-payload_statement(A) ::= . { A = NULL; }
-payload_statement(A) ::= PAYLOAD_KW proto_stack(B) SEMICOLON. { A = B; }
-
-criteria_statement(A) ::= . { A = NULL; }
-criteria_statement(A) ::= CRITERIA_KW accept_mode(B) match_mode(C) avpl(D) SEMICOLON. {
- A = g_malloc(sizeof(pdu_criteria_t));
- A->criterium_avpl = D;
- A->criterium_match_mode = C;
- A->criterium_accept_mode = B;
-}
-
-accept_mode(A) ::= . { A = ACCEPT_MODE; }
-accept_mode(A) ::= ACCEPT_KW. { A = ACCEPT_MODE; }
-accept_mode(A) ::= REJECT_KW. { A = REJECT_MODE; }
-
-extraction_statements(A) ::= extraction_statements(B) extraction_statement(C). { A = B; A->last = A->last->next = C; }
-extraction_statements(A) ::= extraction_statement(B). { A = B; A->last = A; }
-
-extraction_statement(A) ::= EXTRACT_KW NAME(NAME) FROM_KW field(FIELD) SEMICOLON. {
- A = g_malloc(sizeof(extraction_t));
- A->as = NAME;
- A->hfi = FIELD;
- A->next = A->last = NULL;
-}
-
-
-pdu_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; }
-pdu_drop_unassigned_statement(A) ::= . { A = mc->defaults.pdu.drop_unassigned; }
-
-discard_pdu_data_statement(A) ::= DISCARD_PDU_DATA_KW true_false(B) SEMICOLON. { A = B; }
-discard_pdu_data_statement(A) ::= . { A = mc->defaults.pdu.discard; }
-
-last_extracted_statement(A) ::= LAST_PDU_KW true_false(B) SEMICOLON. { A = B; }
-last_extracted_statement(A) ::= . { A = mc->defaults.pdu.last_extracted; }
-
-proto_stack(A) ::= proto_stack(B) SLASH field(C). {
- int* hfidp = g_malloc(sizeof(int));
-
- g_string_sprintfa(mc->fields_filter,"||%s",C->abbrev);
-
- *hfidp = C->id;
- g_ptr_array_add(B,hfidp);
- A = B;
-}
-
-proto_stack(A) ::= field(B). {
- int* hfidp = g_malloc(sizeof(int));
- *hfidp = B->id;
-
- g_string_sprintfa(mc->fields_filter,"||%s",B->abbrev);
-
- A = g_ptr_array_new();
- g_ptr_array_add(A,hfidp);
-}
-
-field(A) ::= NAME(B). {
- A = proto_registrar_get_byname(B);
-}
-
-/******************************************* GOP
-*/
-
-gop_decl(A) ::= GOP_KW NAME(Name) ON_KW pdu_name(PduName) MATCH_KW avpl(Key) OPEN_BRACE
- gop_start_statement(Start)
- gop_stop_statement(Stop)
- extra_statement(Extra)
- transform_list_statement(Transform)
- gop_expiration_statement(Expiration)
- idle_timeout_statement(IdleTimeout)
- lifetime_statement(Lifetime)
- gop_drop_unassigned_statement(DropUnassigned)
- show_goptree_statement(TreeMode)
- show_times_statement(ShowTimes)
- CLOSE_BRACE SEMICOLON. {
- mate_cfg_gop* cfg;
-
- if (g_hash_table_lookup(mc->gopcfgs,Name)) configuration_error(mc,"A Gop Named '%s' exists already.",Name);
- if (g_hash_table_lookup(mc->gops_by_pduname,PduName) ) configuration_error(mc,"Gop for Pdu '%s' exists already",PduName);
-
- cfg = new_gopcfg(Name);
- g_hash_table_insert(mc->gops_by_pduname,PduName,cfg);
- g_hash_table_insert(mc->gopcfgs,cfg->name,cfg);
-
- cfg->on_pdu = PduName;
- cfg->key = Key;
- cfg->drop_unassigned = DropUnassigned;
- cfg->show_times = ShowTimes;
- cfg->pdu_tree_mode = TreeMode;
- cfg->expiration = Expiration;
- cfg->idle_timeout = IdleTimeout;
- cfg->lifetime = Lifetime;
- cfg->start = Start;
- cfg->stop = Stop;
- cfg->transforms = Transform;
-
- merge_avpl(cfg->extra,Extra,TRUE);
- delete_avpl(Extra,TRUE);
-}
-
-gop_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; }
-gop_drop_unassigned_statement(A) ::= . { A = mc->defaults.gop.drop_unassigned; }
-
-gop_start_statement(A) ::= START_KW avpl(B) SEMICOLON. { A = B; }
-gop_start_statement(A) ::= . { A = NULL; }
-
-gop_stop_statement(A) ::= STOP_KW avpl(B) SEMICOLON. { A = B; }
-gop_stop_statement(A) ::= . { A = NULL; }
-
-show_goptree_statement(A) ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { A = B; }
-show_goptree_statement(A) ::= . { A = mc->defaults.gop.pdu_tree_mode; }
-
-show_times_statement(A) ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { A = B; }
-show_times_statement(A) ::= . { A = mc->defaults.gop.show_times; }
-
-gop_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
-gop_expiration_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
-
-idle_timeout_statement(A) ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { A = B; }
-idle_timeout_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
-
-lifetime_statement(A) ::= LIFETIME_KW time_value(B) SEMICOLON. { A = B; }
-lifetime_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
-
-gop_tree_mode(A) ::= NO_TREE_KW. { A = GOP_NO_TREE; }
-gop_tree_mode(A) ::= PDU_TREE_KW. { A = GOP_PDU_TREE; }
-gop_tree_mode(A) ::= FRAME_TREE_KW. { A = GOP_FRAME_TREE; }
-gop_tree_mode(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_PDU_TREE; }
-
-true_false(A) ::= TRUE_KW. { A = TRUE; }
-true_false(A) ::= FALSE_KW. { A = FALSE; }
-
-pdu_name(A) ::= NAME(B). {
- mate_cfg_pdu* c;
- if (( c = g_hash_table_lookup(mc->pducfgs,B) )) {
- A = c->name;
- } else {
- configuration_error(mc,"No such Pdu: '%s'",B);
- }
-}
-
-
-time_value(A) ::= FLOATING(B). {
- A = (float) strtod(B,NULL);
-}
-
-time_value(A) ::= INTEGER(B). {
- A = (float) strtod(B,NULL);
-}
-
-/************* GOG
-*/
-
-gog_decl ::= GOG_KW NAME(Name) OPEN_BRACE
- gog_key_statements(Keys)
- extra_statement(Extra)
- transform_list_statement(Transforms)
- gog_expiration_statement(Expiration)
- gog_goptree_statement(Tree)
- CLOSE_BRACE SEMICOLON. {
- mate_cfg_gog* cfg = NULL;
-
- if ( g_hash_table_lookup(mc->gogcfgs,Name) ) {
- configuration_error(mc,"Gog '%s' exists already ",Name);
- }
-
- cfg = new_gogcfg(Name);
-
- cfg->expiration = Expiration;
- cfg->gop_tree_mode = Tree;
- cfg->transforms = Transforms;
- cfg->keys = Keys;
-
- merge_avpl(cfg->extra,Extra,TRUE);
- delete_avpl(Extra,TRUE);
-}
-
-gog_goptree_statement(A) ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { A = B; }
-gog_goptree_statement(A) ::= . { A = mc->defaults.gog.gop_tree_mode; }
-
-gog_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
-gog_expiration_statement(A) ::= . { A = mc->defaults.gog.expiration; }
-
-gop_tree_type(A) ::= NULL_TREE_KW. { A = GOP_NULL_TREE; }
-gop_tree_type(A) ::= FULL_TREE_KW. { A = GOP_FULL_TREE; }
-gop_tree_type(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_TREE; }
-
-gog_key_statements(A) ::= gog_key_statements(B) gog_key_statement(C). {
- loal_append(B,C);
- A = B;
-}
-
-gog_key_statements(A) ::= gog_key_statement(B). {
- A = new_loal("");
- loal_append(A,B);
-}
-
-
-gog_key_statement(A) ::= MEMBER_KW gop_name(B) avpl(C) SEMICOLON. {
- rename_avpl(C,B);
- A = C;
-}
-
-gop_name(A) ::= NAME(B). {
- mate_cfg_gop* c;
- if (( c = g_hash_table_lookup(mc->gopcfgs,B) )) {
- A = c->name;
- } else {
- configuration_error(mc,"No Gop called '%s' has been already declared",B);
- }
-}
-/******************************************** GENERAL
-*/
-
-
-extra_statement(A) ::= EXTRA_KW avpl(B) SEMICOLON. { A = B; }
-extra_statement(A) ::= . { A = new_avpl(""); }
-
-transform_list_statement(A) ::= TRANSFORM_KW transform_list(B) SEMICOLON. { A = B; }
-transform_list_statement(A) ::= . { A = g_ptr_array_new(); }
-
-transform_list(A) ::= transform_list(B) COMMA transform(C). {
- A = B;
- g_ptr_array_add(B,C);
-}
-
-transform_list(A) ::= transform(B). {
- A = g_ptr_array_new();
- g_ptr_array_add(A,B);
-}
-
-transform(A) ::= NAME(B). {
- AVPL_Transf* t;
-
- if (( t = g_hash_table_lookup(mc->transfs,B) )) {
- A = t;
- } else {
- configuration_error(mc,"There's no such Transformation: %s",B);
- }
-}
-
-avpl(A) ::= OPEN_PARENS avps(B) CLOSE_PARENS. { A = B; }
-avpl(A) ::= OPEN_PARENS CLOSE_PARENS. { A = new_avpl(""); }
-
-avps(A) ::= avps(B) COMMA avp(C). { A = B; if ( ! insert_avp(B,C) ) delete_avp(C); }
-avps(A) ::= avp(B). { A = new_avpl(""); if ( ! insert_avp(A,B) ) delete_avp(B); }
-
-avp(A) ::= NAME(B) AVP_OPERATOR(C) value(D). { A = new_avp(B,D,*C); }
-avp(A) ::= NAME(B). { A = new_avp(B,"",'?'); }
-avp(A) ::= NAME(B) OPEN_BRACE avp_oneoff(C) CLOSE_BRACE. { A = new_avp(B,C,'|'); }
-
-avp_oneoff(A) ::= avp_oneoff(B) PIPE value(C). { A = g_strdup_printf("%s|%s",B,C); }
-avp_oneoff(A) ::= value(B). { A = g_strdup(B); }
-
-value(A) ::= QUOTED(B). { A = g_strdup(B); }
-value(A) ::= NAME(B). { A = g_strdup(B); }
-value(A) ::= FLOATING(B). { A = g_strdup(B); }
-value(A) ::= INTEGER(B). { A = g_strdup(B); }
-value(A) ::= DOTED_IP(B). { A = g_strdup(B); }
-value(A) ::= COLONIZED(B). { A = recolonize(mc,B); }
-
Index: MultiSource/Applications/lemon/xapian_COPYING
===================================================================
--- MultiSource/Applications/lemon/xapian_COPYING
+++ /dev/null
@@ -1,340 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
Index: MultiSource/Applications/lemon/xapian_queryparser.lemony
===================================================================
--- MultiSource/Applications/lemon/xapian_queryparser.lemony
+++ /dev/null
@@ -1,1763 +0,0 @@
-%include {
-/* queryparser.lemony: build a Xapian::Query object from a user query string.
- *
- * Copyright (C) 2004,2005,2006,2007 Olly Betts
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
- * USA
- */
-
-#include
-
-#include "omassert.h"
-#include "queryparser_internal.h"
-#include
-#include
-#include "stringutils.h"
-
-// Include the list of token values lemon generates.
-#include "queryparser_token.h"
-
-#include
-#include
-#include
-
-#include
-
-using namespace std;
-
-using namespace Xapian;
-
-inline bool
-U_isupper(unsigned ch) {
- return (ch < 128 && C_isupper((unsigned char)ch));
-}
-
-inline bool
-U_isdigit(unsigned ch) {
- return (ch < 128 && C_isdigit((unsigned char)ch));
-}
-
-inline bool
-U_isalpha(unsigned ch) {
- return (ch < 128 && C_isalpha((unsigned char)ch));
-}
-
-using Xapian::Unicode::is_whitespace;
-
-inline bool
-is_not_whitespace(unsigned ch) {
- return !is_whitespace(ch);
-}
-
-using Xapian::Unicode::is_wordchar;
-
-inline bool
-is_not_wordchar(unsigned ch) {
- return !is_wordchar(ch);
-}
-
-inline bool
-is_digit(unsigned ch) {
- return (Unicode::get_category(ch) == Unicode::DECIMAL_DIGIT_NUMBER);
-}
-
-// FIXME: we used to keep trailing "-" (e.g. Cl-) but it's of dubious utility
-// and there's the risk of hyphens getting stuck onto the end of terms...
-inline bool
-is_suffix(unsigned ch) {
- return ch == '+' || ch == '#';
-}
-
-inline bool
-prefix_needs_colon(const string & prefix, unsigned ch)
-{
- if (!U_isupper(ch)) return false;
- string::size_type len = prefix.length();
- return (len > 1 && prefix[len - 1] != ':');
-}
-
-using Unicode::is_currency;
-
-/// A structure identifying a group of filter terms.
-struct filter_group_id {
- /** The prefix of the filter terms.
- * This is used for boolean filter terms.
- */
- list prefixes;
-
- /** The value number of the filter terms.
- * This is used for value range terms.
- */
- Xapian::valueno valno;
-
- /// Make a new filter_group_id for boolean filter terms.
- explicit filter_group_id(const list & prefixes_)
- : prefixes(prefixes_), valno(Xapian::BAD_VALUENO) {}
-
- /// Make a new filter_group_id for value range terms.
- explicit filter_group_id(Xapian::valueno valno_)
- : prefixes(), valno(valno_) {}
-
- /// Compare to another filter_group_id.
- bool operator<(const filter_group_id & other) const {
- if (prefixes != other.prefixes) {
- return prefixes < other.prefixes;
- }
- return valno < other.valno;
- }
-};
-
-/** Class used to pass information about a token from lexer to parser.
- *
- * Generally an instance of this class carries term information, but it can be
- * used for the start or end of a value range, with some operators (e.g. the
- * distance in NEAR/3 or ADJ/3, etc).
- */
-class Term {
- State * state;
-
- public:
- string name;
- list prefixes;
- string unstemmed;
- QueryParser::stem_strategy stem;
- termpos pos;
-
- Term(const string &name_, termpos pos_) : name(name_), stem(QueryParser::STEM_NONE), pos(pos_) { }
- Term(const string &name_) : name(name_), stem(QueryParser::STEM_NONE), pos(0) { }
- Term(const string &name_, const list &prefixes_)
- : name(name_), prefixes(prefixes_), stem(QueryParser::STEM_NONE), pos(0) { }
- Term(termpos pos_) : stem(QueryParser::STEM_NONE), pos(pos_) { }
- Term(State * state_, const string &name_, const list &prefixes_,
- const string &unstemmed_,
- QueryParser::stem_strategy stem_ = QueryParser::STEM_NONE,
- termpos pos_ = 0)
- : state(state_), name(name_), prefixes(prefixes_), unstemmed(unstemmed_),
- stem(stem_), pos(pos_) { }
-
- std::string make_term(const string & prefix) const;
-
- void need_positions() {
- if (stem == QueryParser::STEM_SOME) stem = QueryParser::STEM_NONE;
- }
-
- termpos get_termpos() const { return pos; }
-
- filter_group_id get_filter_group_id() const { return filter_group_id(prefixes); }
-
- Query * as_wildcarded_query(State * state) const;
-
- Query * as_partial_query(State * state_) const;
-
- Query get_query() const;
-
- Query get_query_with_synonyms() const;
-
- Query get_query_with_auto_synonyms() const;
-};
-
-/// Parser State shared between the lexer and the parser.
-class State {
- QueryParser::Internal * qpi;
-
- public:
- Query query;
- const char * error;
- unsigned flags;
-
- State(QueryParser::Internal * qpi_, unsigned flags_)
- : qpi(qpi_), error(NULL), flags(flags_) { }
-
- string stem_term(const string &term) {
- return qpi->stemmer(term);
- }
-
- void add_to_stoplist(const Term * term) {
- qpi->stoplist.push_back(term->name);
- }
-
- void add_to_unstem(const string & term, const string & unstemmed) {
- qpi->unstem.insert(make_pair(term, unstemmed));
- }
-
- valueno value_range(Query & q, Term *a, Term *b) {
- string start = a->name;
- string end = b->name;
- Xapian::valueno valno = Xapian::BAD_VALUENO;
- list::const_iterator i;
- for (i = qpi->valrangeprocs.begin(); i != qpi->valrangeprocs.end(); ++i) {
- valno = (**i)(start, end);
- if (valno != Xapian::BAD_VALUENO) {
- delete a;
- delete b;
- q = Query(Query::OP_VALUE_RANGE, valno, start, end);
- return valno;
- }
- }
- // FIXME: Do we want to report an error for this? If not we need
- // to perform the above check in the tokeniser and if none of the
- // ValueRangeProcessor classes like the range, we rollback to
- // parsing the query without treating this as a range. Needs
- // more thought and probably a look at queries users actually
- // enter.
- error = "Unknown range operation";
- return valno;
- }
-
- Query::op default_op() const { return qpi->default_op; }
-
- bool is_stopword(const Term *term) const {
- return qpi->stopper && (*qpi->stopper)(term->name);
- }
-
- Database get_database() const {
- return qpi->db;
- }
-};
-
-string
-Term::make_term(const string & prefix) const
-{
- string term;
- if (stem == QueryParser::STEM_SOME) term += 'Z';
- if (!prefix.empty()) {
- term += prefix;
- if (prefix_needs_colon(prefix, name[0])) term += ':';
- }
- if (stem != QueryParser::STEM_NONE) {
- term += state->stem_term(name);
- } else {
- term += name;
- }
-
- if (!unstemmed.empty())
- state->add_to_unstem(term, unstemmed);
- return term;
-}
-
-Query
-Term::get_query_with_synonyms() const
-{
- Query q = get_query();
-
- // Handle single-word synonyms with each prefix.
- list::const_iterator piter;
- for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
- // First try the unstemmed term:
- string term;
- if (!piter->empty()) {
- term += *piter;
- if (prefix_needs_colon(*piter, name[0])) term += ':';
- }
- term += name;
-
- Xapian::Database db = state->get_database();
- Xapian::TermIterator syn = db.synonyms_begin(term);
- Xapian::TermIterator end = db.synonyms_end(term);
- if (syn == end && stem != QueryParser::STEM_NONE) {
- // If that has no synonyms, try the stemmed form:
- term = 'Z';
- if (!piter->empty()) {
- term += *piter;
- if (prefix_needs_colon(*piter, name[0])) term += ':';
- }
- term += state->stem_term(name);
- syn = db.synonyms_begin(term);
- end = db.synonyms_end(term);
- }
- while (syn != end) {
- q = Query(Query::OP_OR, q, Query(*syn, 1, pos));
- ++syn;
- }
- }
- return q;
-}
-
-Query
-Term::get_query_with_auto_synonyms() const
-{
- if (state->flags & QueryParser::FLAG_AUTO_SYNONYMS)
- return get_query_with_synonyms();
-
- return get_query();
-}
-
-static void
-add_to_query(Query *& q, Query::op op, Query * term)
-{
- Assert(term);
- if (q) {
- *q = Query(op, *q, *term);
- delete term;
- } else {
- q = term;
- }
-}
-
-static void
-add_to_query(Query *& q, Query::op op, const Query & term)
-{
- if (q) {
- *q = Query(op, *q, term);
- } else {
- q = new Query(term);
- }
-}
-
-Query
-Term::get_query() const
-{
- Assert(prefixes.size() >= 1);
- list::const_iterator piter = prefixes.begin();
- Query q(make_term(*piter), 1, pos);
- while (++piter != prefixes.end()) {
- q = Query(Query::OP_OR, q, Query(make_term(*piter), 1, pos));
- }
- return q;
-}
-
-Query *
-Term::as_wildcarded_query(State * state_) const
-{
- Database db = state_->get_database();
- Query * q = new Query;
- list::const_iterator piter;
- for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
- string root = *piter;
- root += name;
- TermIterator t = db.allterms_begin(root);
- while (t != db.allterms_end(root)) {
- add_to_query(q, Query::OP_OR, Query(*t, 1, pos));
- ++t;
- }
- }
- delete this;
- return q;
-}
-
-Query *
-Term::as_partial_query(State * state_) const
-{
- Database db = state_->get_database();
- Query * q = new Query;
- list::const_iterator piter;
- for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
- string root = *piter;
- root += name;
- TermIterator t = db.allterms_begin(root);
- while (t != db.allterms_end(root)) {
- add_to_query(q, Query::OP_OR, Query(*t, 1, pos));
- ++t;
- }
- // Add the term, as it would normally be handled, as an alternative.
- add_to_query(q, Query::OP_OR, Query(make_term(*piter), 1, pos));
- }
- delete this;
- return q;
-}
-
-inline bool
-is_phrase_generator(unsigned ch)
-{
- // These characters generate a phrase search.
- // Ordered mostly by frequency of calls to this function done when
- // running queryparsertest.
- return (ch && ch < 128 && strchr(".-/:\\@", ch) != NULL);
-}
-
-inline bool
-is_stem_preventer(unsigned ch)
-{
- return (ch && ch < 128 && strchr("(/\\@<>=*[{\"", ch) != NULL);
-}
-
-inline bool
-should_stem(const std::string & term)
-{
- const unsigned int SHOULD_STEM_MASK =
- (1 << Unicode::LOWERCASE_LETTER) |
- (1 << Unicode::TITLECASE_LETTER) |
- (1 << Unicode::MODIFIER_LETTER) |
- (1 << Unicode::OTHER_LETTER);
- Utf8Iterator u(term);
- return ((SHOULD_STEM_MASK >> Unicode::get_category(*u)) & 1);
-}
-
-inline unsigned check_infix(unsigned ch) {
- if (ch == '\'' || ch == '&' || ch == 0xb7 || ch == 0x5f4 || ch == 0x2027) {
- // Unicode includes all these except '&' in it's word boundary rules,
- // as well as 0x2019 (which we handle below) and ':' (for Swedish
- // apparently, but we ignore this for now as it's problematic in
- // real world cases).
- return ch;
- }
- // 0x2019 is Unicode apostrophe and single closing quote.
- // 0x201b is Unicode single opening quote with the tail rising.
- if (ch == 0x2019 || ch == 0x201b) return '\'';
- return 0;
-}
-
-inline unsigned check_infix_digit(unsigned ch) {
- // This list of characters comes from Unicode's word identifying algorithm.
- switch (ch) {
- case ',':
- case '.':
- case ';':
- case 0x037e: // GREEK QUESTION MARK
- case 0x0589: // ARMENIAN FULL STOP
- case 0x060D: // ARABIC DATE SEPARATOR
- case 0x07F8: // NKO COMMA
- case 0x2044: // FRACTION SLASH
- case 0xFE10: // PRESENTATION FORM FOR VERTICAL COMMA
- case 0xFE13: // PRESENTATION FORM FOR VERTICAL COLON
- case 0xFE14: // PRESENTATION FORM FOR VERTICAL SEMICOLON
- return ch;
- }
- return 0;
-}
-
-struct yyParser;
-
-// Prototype the functions lemon generates.
-static yyParser *ParseAlloc();
-static void ParseFree(yyParser *);
-static void Parse(yyParser *, int, Term *, State *);
-
-void
-QueryParser::Internal::add_prefix(const string &field, const string &prefix,
- bool filter)
-{
- map::iterator p = prefixmap.find(field);
- if (p == prefixmap.end()) {
- prefixmap.insert(make_pair(field, PrefixInfo(filter, prefix)));
- } else {
- // Check that this is the same type of filter as the existing one(s).
- if (p->second.filter != filter) {
- throw Xapian::InvalidOperationError("Can't use add_prefix() and add_bool_prefix() on the same field name");
- }
- p->second.prefixes.push_back(prefix);
- }
-}
-
-string
-QueryParser::Internal::parse_term(Utf8Iterator &it, const Utf8Iterator &end,
- bool &was_acronym)
-{
- string term;
- // Look for initials separated by '.' (e.g. P.T.O., U.N.C.L.E).
- // Don't worry if there's a trailing '.' or not.
- if (U_isupper(*it)) {
- string t;
- Utf8Iterator p = it;
- do {
- Unicode::append_utf8(t, *p++);
- } while (p != end && *p == '.' && ++p != end && U_isupper(*p));
- // One letter does not make an acronym! If we handled a single
- // uppercase letter here, we wouldn't catch M&S below.
- if (t.length() > 1) {
- // Check there's not a (lower case) letter or digit
- // immediately after it.
- // FIXME: should I.B.M..P.T.O be a range search?
- if (p == end || !is_wordchar(*p)) {
- it = p;
- swap(term, t);
- }
- }
- }
- was_acronym = !term.empty();
-
- if (term.empty()) {
- unsigned prevch = *it;
- Unicode::append_utf8(term, prevch);
- while (++it != end) {
- unsigned ch = *it;
- if (!is_wordchar(ch)) {
- // Treat a single embedded '&' or "'" or similar as a word
- // character (e.g. AT&T, Fred's). Also, normalise
- // apostrophes to ASCII apostrophe.
- Utf8Iterator p = it;
- ++p;
- if (p == end || !is_wordchar(*p)) break;
- unsigned nextch = *p;
- if (is_digit(prevch) &&
- is_digit(nextch)) {
- ch = check_infix_digit(ch);
- } else {
- ch = check_infix(ch);
- }
- if (!ch) break;
- }
- Unicode::append_utf8(term, ch);
- prevch = ch;
- }
- if (it != end && is_suffix(*it)) {
- string suff_term = term;
- Utf8Iterator p = it;
- // Keep trailing + (e.g. C++, Na+) or # (e.g. C#).
- do {
- if (suff_term.size() - term.size() == 3) {
- suff_term.resize(0);
- break;
- }
- suff_term += *p;
- } while (is_suffix(*++p));
- if (!suff_term.empty() && (p == end || !is_wordchar(*p))) {
- // If the suffixed term doesn't exist, check that the
- // non-suffixed term does. This also takes care of
- // the case when QueryParser::set_database() hasn't
- // been called.
- bool use_suff_term = false;
- string lc = Unicode::tolower(suff_term);
- if (db.term_exists(lc)) {
- use_suff_term = true;
- } else {
- lc = Unicode::tolower(term);
- if (!db.term_exists(lc)) use_suff_term = true;
- }
- if (use_suff_term) {
- term = suff_term;
- it = p;
- }
- }
- }
- }
- return term;
-}
-
-Query
-QueryParser::Internal::parse_query(const string &qs, unsigned flags,
- const string &default_prefix)
-{
- yyParser * pParser = ParseAlloc();
-
- // Set value_ranges if we may have to handle value ranges in the query.
- bool value_ranges;
- value_ranges = !valrangeprocs.empty() && (qs.find("..") != string::npos);
-
- termpos term_pos = 1;
- Utf8Iterator it(qs), end;
-
- State state(this, flags);
-
- // To successfully apply more than one spelling correction to a query
- // string, we must keep track of the offset due to previous corrections.
- int correction_offset = 0;
- corrected_query.resize(0);
-
- // Stack of prefixes, used for phrases and subexpressions.
- list prefix_stack;
-
- // If default_prefix is specified, use it. Otherwise, use any list
- // that has been set for the empty prefix.
- const PrefixInfo def_pfx(false, default_prefix);
- {
- const PrefixInfo * default_prefixinfo = &def_pfx;
- if (default_prefix.empty()) {
- map::const_iterator f = prefixmap.find("");
- if (f != prefixmap.end()) default_prefixinfo = &(f->second);
- }
-
- // We always have the current prefix on the top of the stack.
- prefix_stack.push_back(default_prefixinfo);
- }
-
- unsigned newprev = ' ';
-main_lex_loop:
- enum {
- DEFAULT, IN_QUOTES, IN_PREFIXED_QUOTES, IN_PHRASED_TERM, IN_GROUP
- } mode = DEFAULT;
- while (it != end) {
- bool last_was_operator = false;
- if (false) {
-just_had_operator:
- if (it == end) break;
- last_was_operator = true;
- mode = DEFAULT;
- }
- if (mode == IN_PHRASED_TERM) mode = DEFAULT;
- if (is_whitespace(*it)) {
- newprev = ' ';
- ++it;
- it = find_if(it, end, is_not_whitespace);
- if (it == end) break;
- }
-
- if ((mode == DEFAULT || mode == IN_GROUP) && value_ranges) {
- // Scan forward to see if this could be the "start of range"
- // token. Sadly this has O(n^2) tendencies, though at least
- // "n" is the number of words in a query which is likely to
- // remain fairly small. FIXME: can we tokenise more elegantly?
- Utf8Iterator p = it;
- unsigned ch = 0;
- while (p != end) {
- if (ch == '.' && *p == '.') {
- ++p;
- if (p == end || *p <= ' ' || *p == ')') break;
-
- string r;
- do {
- Unicode::append_utf8(r, *it++);
- } while (it != p);
- // Trim off the trailing "..".
- r.resize(r.size() - 2);
- Parse(pParser, RANGE_START, new Term(r), &state);
- r.resize(0);
- // Allow any character except whitespace and ')' in a
- // RANGE_END. Or should we be consistent with RANGE_START?
- do {
- Unicode::append_utf8(r, *p++);
- } while (p != end && *p > ' ' && *p != ')');
- Parse(pParser, RANGE_END, new Term(r), &state);
- it = p;
- goto main_lex_loop;
- }
- ch = *p;
- if (!(is_wordchar(ch) || is_currency(ch) ||
- (ch < 128 && strchr("%,-./:@", ch)))) break;
- ++p;
- }
- }
-
- if (!is_wordchar(*it)) {
- unsigned prev = newprev;
- unsigned ch = *it++;
- newprev = ch;
- // Drop out of IN_GROUP mode.
- if (mode == IN_GROUP) mode = DEFAULT;
- switch (ch) {
- case '"': // Quoted phrase.
- if (mode == DEFAULT) {
- // Skip whitespace.
- it = find_if(it, end, is_not_whitespace);
- if (it == end) {
- // Ignore an unmatched " at the end of the query to
- // avoid generating an empty pair of QUOTEs which will
- // cause a parse error.
- goto done;
- }
- if (*it == '"') {
- // Ignore empty "" (but only if we're not already
- // IN_QUOTES as we don't merge two adjacent quoted
- // phrases!)
- newprev = *it++;
- break;
- }
- }
- if (flags & QueryParser::FLAG_PHRASE) {
- Parse(pParser, QUOTE, NULL, &state);
- if (mode == DEFAULT) {
- mode = IN_QUOTES;
- } else {
- // Remove the prefix we pushed for this phrase.
- if (mode == IN_PREFIXED_QUOTES)
- prefix_stack.pop_back();
- mode = DEFAULT;
- }
- }
- break;
-
- case '+': case '-': // Loved or hated term/phrase/subexpression.
- // Ignore + or - at the end of the query string.
- if (it == end) goto done;
- if (prev > ' ' && prev != '(') {
- // Or if not after whitespace or an open bracket.
- break;
- }
- if (is_whitespace(*it) || *it == '+' || *it == '-') {
- // Ignore + or - followed by a space, or further + or -.
- // Postfix + (such as in C++ and H+) is handled as part of
- // the term lexing code in parse_term().
- newprev = *it++;
- break;
- }
- if (mode == DEFAULT && (flags & FLAG_LOVEHATE)) {
- Parse(pParser, (ch == '+' ? LOVE : HATE), NULL, &state);
- goto just_had_operator;
- }
- // Need to prevent the term after a LOVE or HATE starting a
- // term group...
- break;
-
- case '(': // Bracketed subexpression.
- // Skip whitespace.
- it = find_if(it, end, is_not_whitespace);
- // Ignore ( at the end of the query string.
- if (it == end) goto done;
- if (prev > ' ' && strchr("()+-", prev) == NULL) {
- // Or if not after whitespace or a bracket or '+' or '-'.
- break;
- }
- if (*it == ')') {
- // Ignore empty ().
- newprev = *it++;
- break;
- }
- if (mode == DEFAULT && (flags & FLAG_BOOLEAN)) {
- prefix_stack.push_back(prefix_stack.back());
- Parse(pParser, BRA, NULL, &state);
- }
- break;
-
- case ')': // End of bracketed subexpression.
- if (mode == DEFAULT && (flags & FLAG_BOOLEAN)) {
- // Remove the prefix we pushed for the corresponding BRA.
- // If brackets are unmatched, it's a syntax error, but
- // that's no excuse to SEGV!
- if (prefix_stack.size() > 1) prefix_stack.pop_back();
- Parse(pParser, KET, NULL, &state);
- }
- break;
-
- case '~': // Synonym expansion.
- // Ignore at the end of the query string.
- if (it == end) goto done;
- if (prev > ' ' && prev != '+' && prev != '-' && prev != '(') {
- // Or if not after whitespace, +, -, or an open bracket.
- break;
- }
- if (!is_wordchar(*it)) {
- // Ignore if not followed by a word character.
- break;
- }
- if (mode == DEFAULT && (flags & FLAG_SYNONYM)) {
- Parse(pParser, SYNONYM, NULL, &state);
- goto just_had_operator;
- }
- break;
- }
- // Skip any other characters.
- continue;
- }
-
- Assert(is_wordchar(*it));
-
- size_t term_start_index = it.raw() - qs.data();
-
- newprev = 'A'; // Any letter will do...
-
- // A term, a prefix, or a boolean operator.
- const PrefixInfo * prefixinfo = NULL;
- if ((mode == DEFAULT || mode == IN_GROUP) && !prefixmap.empty()) {
- // Check for a fieldname prefix (e.g. title:historical).
- Utf8Iterator p = find_if(it, end, is_not_wordchar);
- if (p != end && *p == ':' && ++p != end && *p > ' ' && *p != ')') {
- string field;
- p = it;
- while (*p != ':')
- Unicode::append_utf8(field, *p++);
- map::const_iterator f;
- f = prefixmap.find(field);
- if (f != prefixmap.end()) {
- // Special handling for prefixed fields, depending on the
- // type of the prefix.
- unsigned ch = *++p;
- prefixinfo = &(f->second);
-
- if (prefixinfo->filter) {
- // Drop out of IN_GROUP if we're in it.
- mode = DEFAULT;
- // Can't boolean filter prefix a subexpression or
- // phrase; just use anything following the prefix
- // until the next space or ')' as part of the boolean
- // filter term.
- it = p;
- string name;
- while (it != end && *it > ' ' && *it != ')')
- Unicode::append_utf8(name, *it++);
- // Build the unstemmed form in field.
- field += ':';
- field += name;
- const list & prefixes = prefixinfo->prefixes;
- Term * token = new Term(&state, name, prefixes, field);
- Parse(pParser, BOOLEAN_FILTER, token, &state);
- continue;
- }
-
- if (ch == '"' && (flags & FLAG_PHRASE)) {
- // Prefixed phrase, e.g.: subject:"space flight"
- mode = IN_PREFIXED_QUOTES;
- Parse(pParser, QUOTE, NULL, &state);
- it = p;
- newprev = ch;
- ++it;
- prefix_stack.push_back(prefixinfo);
- continue;
- }
-
- if (ch == '(' && (flags & FLAG_BOOLEAN)) {
- // Prefixed subexpression, e.g.: title:(fast NEAR food)
- mode = DEFAULT;
- Parse(pParser, BRA, NULL, &state);
- it = p;
- newprev = ch;
- ++it;
- prefix_stack.push_back(prefixinfo);
- continue;
- }
-
- if (is_wordchar(ch)) {
- // Prefixed term.
- it = p;
- } else {
- // It looks like a prefix but isn't, so parse it as
- // text instead.
- prefixinfo = NULL;
- }
- }
- }
- }
-
-phrased_term:
- bool was_acronym;
- string term = parse_term(it, end, was_acronym);
-
- // Boolean operators.
- if ((mode == DEFAULT || mode == IN_GROUP) &&
- (flags & FLAG_BOOLEAN) &&
- // Don't want to interpret A.N.D. as an AND operator.
- !was_acronym &&
- !prefixinfo &&
- term.size() >= 2 && term.size() <= 4 && U_isalpha(term[0])) {
-
- string op = term;
- if (flags & FLAG_BOOLEAN_ANY_CASE) {
- for (string::iterator i = op.begin(); i != op.end(); ++i) {
- *i = C_toupper(*i);
- }
- }
- if (op.size() == 3) {
- if (op == "AND") {
- Parse(pParser, AND, NULL, &state);
- goto just_had_operator;
- }
- if (op == "NOT") {
- Parse(pParser, NOT, NULL, &state);
- goto just_had_operator;
- }
- if (op == "XOR") {
- Parse(pParser, XOR, NULL, &state);
- goto just_had_operator;
- }
- if (op == "ADJ") {
- if (it != end && *it == '/') {
- size_t width = 0;
- Utf8Iterator p = it;
- while (++p != end && U_isdigit(*p)) {
- width = (width * 10) + (*p - '0');
- }
- if (width && (p == end || is_whitespace(*p))) {
- it = p;
- Parse(pParser, ADJ, new Term(width), &state);
- goto just_had_operator;
- }
- }
-
- Parse(pParser, ADJ, NULL, &state);
- goto just_had_operator;
- }
- } else if (op.size() == 2) {
- if (op == "OR") {
- Parse(pParser, OR, NULL, &state);
- goto just_had_operator;
- }
- } else if (op.size() == 4) {
- if (op == "NEAR") {
- if (it != end && *it == '/') {
- size_t width = 0;
- Utf8Iterator p = it;
- while (++p != end && U_isdigit(*p)) {
- width = (width * 10) + (*p - '0');
- }
- if (width && (p == end || is_whitespace(*p))) {
- it = p;
- Parse(pParser, NEAR, new Term(width), &state);
- goto just_had_operator;
- }
- }
-
- Parse(pParser, NEAR, NULL, &state);
- goto just_had_operator;
- }
- }
- }
-
- // If no prefix is set, use the default one.
- if (!prefixinfo) prefixinfo = prefix_stack.back();
-
- Assert(!prefixinfo->filter);
-
- {
- string unstemmed_term(term);
- term = Unicode::tolower(term);
-
- // Reuse stem_strategy - STEM_SOME here means "stem terms except
- // when used with positional operators".
- stem_strategy stem_term = stem_action;
- if (stem_term != STEM_NONE) {
- if (!stemmer.internal.get()) {
- // No stemmer is set.
- stem_term = STEM_NONE;
- } else if (stem_term == STEM_SOME) {
- if (!should_stem(unstemmed_term) ||
- (it != end && is_stem_preventer(*it))) {
- // Don't stem this particular term.
- stem_term = STEM_NONE;
- }
- }
- }
-
- Term * term_obj = new Term(&state, term, prefixinfo->prefixes,
- unstemmed_term, stem_term, term_pos++);
-
- // Check spelling, if we're a normal term, and any of the prefixes
- // are empty.
- if ((flags & FLAG_SPELLING_CORRECTION) && !was_acronym) {
- list::const_iterator prefixiter;
- for (prefixiter = prefixinfo->prefixes.begin();
- prefixiter != prefixinfo->prefixes.end();
- ++prefixiter) {
- if (!prefixiter->empty())
- continue;
- if (!db.term_exists(term)) {
- string suggestion = db.get_spelling_suggestion(term);
- if (!suggestion.empty()) {
- if (corrected_query.empty()) corrected_query = qs;
- size_t term_end_index = it.raw() - qs.data();
- size_t n = term_end_index - term_start_index;
- size_t pos = term_start_index + correction_offset;
- corrected_query.replace(pos, n, suggestion);
- correction_offset += suggestion.size();
- correction_offset -= n;
- }
- }
- break;
- }
- }
-
- if (mode == IN_PHRASED_TERM) {
- Parse(pParser, PHR_TERM, term_obj, &state);
- } else {
- if (mode == DEFAULT || mode == IN_GROUP) {
- if (it != end) {
- if ((flags & FLAG_WILDCARD) && *it == '*') {
- Utf8Iterator p(it);
- ++p;
- if (p == end || !is_wordchar(*p)) {
- it = p;
- // Wildcard at end of term (also known as
- // "right truncation").
- Parse(pParser, WILD_TERM, term_obj, &state);
- continue;
- }
- }
- } else {
- if (flags & FLAG_PARTIAL) {
- // Final term of a partial match query, with no
- // following characters - treat as a wildcard.
- Parse(pParser, PARTIAL_TERM, term_obj, &state);
- continue;
- }
- }
- }
-
- // See if the next token will be PHR_TERM - if so, this one
- // needs to be TERM not GROUP_TERM.
- if (mode == IN_GROUP && is_phrase_generator(*it)) {
- // FIXME: can we clean this up?
- Utf8Iterator p = it;
- do {
- ++p;
- } while (p != end && is_phrase_generator(*p));
- // Don't generate a phrase unless the phrase generators are
- // immediately followed by another term.
- if (p != end && is_wordchar(*p)) {
- mode = DEFAULT;
- }
- }
-
- Parse(pParser, (mode == IN_GROUP ? GROUP_TERM : TERM),
- term_obj, &state);
- if (mode != DEFAULT && mode != IN_GROUP) continue;
- }
- }
-
- if (it == end) break;
-
- if (is_phrase_generator(*it)) {
- // Skip multiple phrase generators.
- do {
- ++it;
- } while (it != end && is_phrase_generator(*it));
- // Don't generate a phrase unless the phrase generators are
- // immediately followed by another term.
- if (it != end && is_wordchar(*it)) {
- mode = IN_PHRASED_TERM;
- term_start_index = it.raw() - qs.data();
- goto phrased_term;
- }
- } else if (mode == DEFAULT || mode == IN_GROUP) {
- mode = DEFAULT;
- if (!last_was_operator && is_whitespace(*it)) {
- newprev = ' ';
- // Skip multiple whitespace.
- do {
- ++it;
- } while (it != end && is_whitespace(*it));
- // Don't generate a group unless the terms are only separated
- // by whitespace.
- if (it != end && is_wordchar(*it)) {
- mode = IN_GROUP;
- }
- }
- }
- }
-done:
- // Implicitly close any unclosed quotes...
- if (mode == IN_QUOTES || mode == IN_PREFIXED_QUOTES)
- Parse(pParser, QUOTE, NULL, &state);
- Parse(pParser, 0, NULL, &state);
- ParseFree(pParser);
-
- errmsg = state.error;
- return state.query;
-}
-
-struct ProbQuery {
- Query * query;
- Query * love;
- Query * hate;
- // filter is a map from prefix to a query for that prefix. Queries with
- // the same prefix are combined with OR, and the results of this are
- // combined with AND to get the full filter.
- map filter;
-
- ProbQuery() : query(0), love(0), hate(0) { }
- ~ProbQuery() {
- delete query;
- delete love;
- delete hate;
- }
-
- Query merge_filters() const {
- map::const_iterator i = filter.begin();
- Assert(i != filter.end());
- Query q = i->second;
- while (++i != filter.end()) {
- q = Query(Query::OP_AND, q, i->second);
- }
- return q;
- }
-};
-
-class TermGroup {
- list terms;
-
- public:
- TermGroup() { }
-
- /// Add a Term object to this TermGroup object.
- void add_term(Term * term) {
- terms.push_back(term);
- }
-
- /// Convert to a Xapian::Query * using default_op.
- Query * as_group(State *state) const;
-
- /** Provide a way to explicitly delete an object of this class. The
- * destructor is protected to prevent auto-variables of this type.
- */
- void destroy() { delete this; }
-
- protected:
- /** Protected destructor, so an auto-variable of this type is a
- * compile-time error - you must allocate this object with new.
- */
- ~TermGroup() {
- list::const_iterator i;
- for (i = terms.begin(); i != terms.end(); ++i) {
- delete *i;
- }
- }
-};
-
-Query *
-TermGroup::as_group(State *state) const
-{
- Query * query = NULL;
- Query::op default_op = state->default_op();
- if (state->flags & QueryParser::FLAG_AUTO_MULTIWORD_SYNONYMS) {
- // Check for multi-word synonyms.
- Database db = state->get_database();
-
- string key;
- list::const_iterator begin = terms.begin();
- list::const_iterator i = begin;
- while (i != terms.end()) {
- key.resize(0);
- while (i != terms.end()) {
- if (!key.empty()) key += ' ';
- key += (*i)->name;
- ++i;
- }
- // Greedily try to match as many consecutive words as possible.
- TermIterator syn, end;
- while (true) {
- syn = db.synonyms_begin(key);
- end = db.synonyms_end(key);
- if (syn != end) break;
- if (--i == begin) break;
- key.resize(key.size() - (*i)->name.size() - 1);
- }
- if (i == begin) {
- // No multi-synonym matches.
- if (state->is_stopword(*i)) {
- state->add_to_stoplist(*i);
- } else {
- add_to_query(query, default_op,
- (*i)->get_query_with_auto_synonyms());
- }
- begin = ++i;
- continue;
- }
-
- Query * q = NULL;
- list::const_iterator j;
- for (j = begin; j != i; ++j) {
- if (state->is_stopword(*j)) {
- state->add_to_stoplist(*j);
- } else {
- add_to_query(q, default_op, (*j)->get_query());
- }
- }
-
- // Use the position of the first term for the synonyms.
- Xapian::termpos pos = (*begin)->pos;
- begin = i;
- while (syn != end) {
- add_to_query(q, Query::OP_OR, Query(*syn, 1, pos));
- ++syn;
- }
- add_to_query(query, default_op, q);
- }
- } else {
- list::const_iterator i;
- for (i = terms.begin(); i != terms.end(); ++i) {
- if (state->is_stopword(*i)) {
- state->add_to_stoplist(*i);
- } else {
- add_to_query(query, default_op,
- (*i)->get_query_with_auto_synonyms());
- }
- }
- }
- delete this;
- return query;
-}
-
-class TermList {
- list terms;
- size_t window;
-
- /** Keep track of whether the terms added all have the same list of
- * prefixes. If so, we'll build a set of phrases, one using each prefix.
- * This works around the limitation that a phrase cannot have multiple
- * components which are "OR" combinations of terms, but is also probably
- * what users expect: ie, if a user specifies a phrase in a field, and that
- * field maps to multiple prefixes, the user probably wants a phrase
- * returned with all terms having one of those prefixes, rather than a
- * phrase comprised of terms with differing prefixes.
- */
- bool uniform_prefixes;
-
- /** The list of prefixes of the terms added.
- * This will be empty if the terms have different prefixes.
- */
- list prefixes;
-
- public:
- TermList() : window(0), uniform_prefixes(true) { }
-
- /// Add an unstemmed Term object to this TermList object.
- void add_positional_term(Term * term) {
- if (terms.empty()) {
- prefixes = term->prefixes;
- } else if (uniform_prefixes && prefixes != term->prefixes) {
- prefixes.clear();
- uniform_prefixes = false;
- }
- term->need_positions();
- terms.push_back(term);
- }
-
- void adjust_window(size_t alternative_window) {
- if (alternative_window > window) window = alternative_window;
- }
-
- /// Convert to a query using the given operator and window size.
- Query * as_opwindow_query(Query::op op, Xapian::termcount w_delta) const {
- Query * q = NULL;
- // Call terms.size() just once since std::list::size() may be O(n).
- size_t n_terms = terms.size();
- Xapian::termcount w = w_delta + terms.size();
- if (uniform_prefixes) {
- list::const_iterator piter;
- for (piter = prefixes.begin(); piter != prefixes.end(); ++piter) {
- vector subqs;
- subqs.reserve(n_terms);
- list::const_iterator titer;
- for (titer = terms.begin(); titer != terms.end(); ++titer) {
- Term * t = *titer;
- subqs.push_back(Query(t->make_term(*piter), 1, t->pos));
- }
- add_to_query(q, Query::OP_OR,
- Query(op, subqs.begin(), subqs.end(), w));
- }
- } else {
- vector subqs;
- subqs.reserve(n_terms);
- list::const_iterator titer;
- for (titer = terms.begin(); titer != terms.end(); ++titer) {
- subqs.push_back((*titer)->get_query());
- }
- q = new Query(op, subqs.begin(), subqs.end(), w);
- }
-
- delete this;
- return q;
- }
-
- /// Convert to a Xapian::Query * using adjacent OP_PHRASE.
- Query * as_phrase_query() const {
- return as_opwindow_query(Query::OP_PHRASE, 0);
- }
-
- /// Convert to a Xapian::Query * using OP_NEAR.
- Query * as_near_query() const {
- // The common meaning of 'a NEAR b' is "a within 10 terms of b", which
- // means a window size of 11. For more than 2 terms, we just add one
- // to the window size for each extra term.
- size_t w = window;
- if (w == 0) w = 10;
- return as_opwindow_query(Query::OP_NEAR, w - 1);
- }
-
- /// Convert to a Xapian::Query * using OP_PHRASE to implement ADJ.
- Query * as_adj_query() const {
- // The common meaning of 'a ADJ b' is "a at most 10 terms before b",
- // which means a window size of 11. For more than 2 terms, we just add
- // one to the window size for each extra term.
- size_t w = window;
- if (w == 0) w = 10;
- return as_opwindow_query(Query::OP_PHRASE, w - 1);
- }
-
- /** Provide a way to explicitly delete an object of this class. The
- * destructor is protected to prevent auto-variables of this type.
- */
- void destroy() { delete this; }
-
- protected:
- /** Protected destructor, so an auto-variable of this type is a
- * compile-time error - you must allocate this object with new.
- */
- ~TermList() {
- list::const_iterator t;
- for (t = terms.begin(); t != terms.end(); ++t) {
- delete *t;
- }
- }
-};
-
-// Helper macro for converting a boolean operation into a Xapian::Query.
-#define BOOL_OP_TO_QUERY(E, A, OP, B, OP_TXT) \
- do {\
- if (!A || !B) {\
- state->error = "Syntax: "OP_TXT" ";\
- yy_parse_failed(yypParser);\
- return;\
- }\
- E = new Query(OP, *A, *B);\
- delete A;\
- delete B;\
- } while (0)
-
-}
-
-%token_type {Term *}
-%token_destructor {delete $$;}
-
-%extra_argument {State * state}
-
-%parse_failure {
- // If we've not already set an error message, set a default one.
- if (!state->error) state->error = "parse error";
-}
-
-// Operators, grouped in order of increasing precedence:
-%nonassoc ERROR.
-%left OR.
-%left XOR.
-%left AND NOT.
-%left NEAR ADJ.
-%left LOVE HATE SYNONYM.
-
-// Destructors for terminal symbols:
-
-// TERM is a query term, including prefix (if any).
-%destructor TERM {delete $$;}
-
-// GROUP_TERM is a query term which follows a TERM or another GROUP_TERM and
-// is only separated by whitespace characters.
-%destructor GROUP_TERM {delete $$;}
-
-// PHR_TERM is a query term which follows a TERM or another PHR_TERM and is
-// separated only by one or more phrase generator characters (hyphen and
-// apostrophe are common examples - see is_phrase_generator() for the list
-// of all punctuation which does this).
-%destructor PHR_TERM {delete $$;}
-
-// WILD_TERM is like a TERM, but has a trailing wildcard which needs to be
-// expanded.
-%destructor WILD_TERM {delete $$;}
-
-// PARTIAL_TERM is like a TERM, but it's at the end of the query string and
-// we're doing "search as you type". It expands to something like WILD_TERM
-// OR stemmed_form.
-%destructor PARTIAL_TERM {delete $$;}
-
-// BOOLEAN_FILTER is a query term with a prefix registered using
-// add_bool_prefix(). It's added to the query using an OP_FILTER operator,
-// (or OP_AND_NOT if it's negated) e.g. site:xapian.org or -site:xapian.org
-%destructor BOOLEAN_FILTER {delete $$;}
-
-// Grammar rules:
-
-// query - The whole query - just an expr or nothing.
-
-// query non-terminal doesn't need a type, so just give a dummy one.
-%type query {int}
-
-query ::= expr(E). {
- // Save the parsed query in the State structure so we can return it.
- if (E) {
- state->query = *E;
- delete E;
- } else {
- state->query = Query();
- }
-}
-
-query ::= . {
- // Handle a query string with no terms in.
- state->query = Query();
-}
-
-// expr - A query expression.
-
-%type expr {Query *}
-%destructor expr {delete $$;}
-
-expr(E) ::= prob_expr(P).
- { E = P; }
-
-expr(E) ::= bool_arg(A) AND bool_arg(B).
- { BOOL_OP_TO_QUERY(E, A, Query::OP_AND, B, "AND"); }
-
-expr(E) ::= bool_arg(A) NOT bool_arg(B). {
- // 'NOT foo' -> ' NOT foo'
- if (!A && (state->flags & QueryParser::FLAG_PURE_NOT)) {
- A = new Query("", 1, 0);
- }
- BOOL_OP_TO_QUERY(E, A, Query::OP_AND_NOT, B, "NOT");
-}
-
-expr(E) ::= bool_arg(A) AND NOT bool_arg(B). [NOT]
- { BOOL_OP_TO_QUERY(E, A, Query::OP_AND_NOT, B, "AND NOT"); }
-
-expr(E) ::= bool_arg(A) OR bool_arg(B).
- { BOOL_OP_TO_QUERY(E, A, Query::OP_OR, B, "OR"); }
-
-expr(E) ::= bool_arg(A) XOR bool_arg(B).
- { BOOL_OP_TO_QUERY(E, A, Query::OP_XOR, B, "XOR"); }
-
-// bool_arg - an argument to a boolean operator such as AND or OR.
-
-%type bool_arg {Query *}
-%destructor bool_arg {delete $$;}
-
-bool_arg(A) ::= expr(E). { A = E; }
-
-bool_arg(A) ::= . [ERROR] {
- // Set the argument to NULL, which enables the bool_arg-using rules in
- // expr above to report uses of AND, OR, etc which don't have two
- // arguments.
- A = NULL;
-}
-
-// prob_expr - a single compound term, or a prob.
-
-%type prob_expr {Query *}
-%destructor prob_expr {delete $$;}
-
-prob_expr(E) ::= prob(P). {
- E = P->query;
- P->query = NULL;
- // Handle any "+ terms".
- if (P->love) {
- if (P->love->empty()) {
- // +.
- delete E;
- E = P->love;
- } else if (E) {
- swap(E, P->love);
- add_to_query(E, Query::OP_AND_MAYBE, P->love);
- } else {
- E = P->love;
- }
- P->love = NULL;
- }
- // Handle any boolean filters.
- if (!P->filter.empty()) {
- if (E) {
- add_to_query(E, Query::OP_FILTER, P->merge_filters());
- } else {
- // Make the query a boolean one.
- E = new Query(Query::OP_SCALE_WEIGHT, P->merge_filters(), 0.0);
- }
- }
- // Handle any "- terms".
- if (P->hate && !P->hate->empty()) {
- if (!E) {
- // Can't just hate!
- yy_parse_failed(yypParser);
- return;
- }
- *E = Query(Query::OP_AND_NOT, *E, *P->hate);
- }
- // FIXME what if E && E->empty() (all terms are stopwords)?
- delete P;
-}
-
-prob_expr(E) ::= term(T). {
- E = T;
-}
-
-// prob - a probabilistic sub-expression consisting of stop_terms, "+" terms,
-// "-" terms, boolean filters, and/or value ranges.
-//
-// Note: stop_term can also be several other things other than a simple term!
-
-%type prob {ProbQuery *}
-%destructor prob {delete $$;}
-
-prob(P) ::= RANGE_START(A) RANGE_END(B). {
- Query range;
- Xapian::valueno valno = state->value_range(range, A, B);
- if (valno == BAD_VALUENO) {
- yy_parse_failed(yypParser);
- return;
- }
- P = new ProbQuery;
- P->filter[filter_group_id(valno)] = range;
-}
-
-prob(P) ::= stop_prob(Q) RANGE_START(A) RANGE_END(B). {
- Query range;
- Xapian::valueno valno = state->value_range(range, A, B);
- if (valno == BAD_VALUENO) {
- yy_parse_failed(yypParser);
- return;
- }
- P = Q;
- Query & q = P->filter[filter_group_id(valno)];
- q = Query(Query::OP_OR, q, range);
-}
-
-prob(P) ::= stop_term(T) stop_term(U). {
- P = new ProbQuery;
- P->query = T;
- if (U) add_to_query(P->query, state->default_op(), U);
-}
-
-prob(P) ::= prob(Q) stop_term(T). {
- P = Q;
- // If T is a stopword, there's nothing to do here.
- if (T) add_to_query(P->query, state->default_op(), T);
-}
-
-prob(P) ::= LOVE term(T). {
- P = new ProbQuery;
- if (state->default_op() == Query::OP_AND) {
- P->query = T;
- } else {
- P->love = T;
- }
-}
-
-prob(P) ::= stop_prob(Q) LOVE term(T). {
- P = Q;
- if (state->default_op() == Query::OP_AND) {
- /* The default op is AND, so we just put loved terms into the query
- * (in this case the only effect of love is to ignore the stopword
- * list). */
- add_to_query(P->query, Query::OP_AND, T);
- } else {
- add_to_query(P->love, Query::OP_AND, T);
- }
-}
-
-prob(P) ::= HATE term(T). {
- P = new ProbQuery;
- P->hate = T;
-}
-
-prob(P) ::= stop_prob(Q) HATE term(T). {
- P = Q;
- add_to_query(P->hate, Query::OP_OR, T);
-}
-
-prob(P) ::= HATE BOOLEAN_FILTER(T). {
- P = new ProbQuery;
- P->hate = new Query(T->get_query());
- delete T;
-}
-
-prob(P) ::= stop_prob(Q) HATE BOOLEAN_FILTER(T). {
- P = Q;
- add_to_query(P->hate, Query::OP_OR, T->get_query());
- delete T;
-}
-
-prob(P) ::= BOOLEAN_FILTER(T). {
- P = new ProbQuery;
- P->filter[T->get_filter_group_id()] = T->get_query();
- delete T;
-}
-
-prob(P) ::= stop_prob(Q) BOOLEAN_FILTER(T). {
- P = Q;
- // We OR filters with the same prefix...
- Query & q = P->filter[T->get_filter_group_id()];
- q = Query(Query::OP_OR, q, T->get_query());
- delete T;
-}
-
-prob(P) ::= LOVE BOOLEAN_FILTER(T). {
- // LOVE BOOLEAN_FILTER(T) is just the same as BOOLEAN_FILTER
- P = new ProbQuery;
- P->filter[T->get_filter_group_id()] = T->get_query();
- delete T;
-}
-
-prob(P) ::= stop_prob(Q) LOVE BOOLEAN_FILTER(T). {
- // LOVE BOOLEAN_FILTER(T) is just the same as BOOLEAN_FILTER
- P = Q;
- // We OR filters with the same prefix...
- Query & q = P->filter[T->get_filter_group_id()];
- q = Query(Query::OP_OR, q, T->get_query());
- delete T;
-}
-
-// stop_prob - A prob or a stop_term.
-
-%type stop_prob {ProbQuery *}
-%destructor stop_prob {delete $$;}
-
-stop_prob(P) ::= prob(Q).
- { P = Q; }
-
-stop_prob(P) ::= stop_term(T). {
- P = new ProbQuery;
- P->query = T;
-}
-
-// stop_term - A term which should be checked against the stopword list,
-// or a compound_term.
-//
-// If a term is loved, hated, or in a phrase, we don't want to consult the
-// stopword list, so stop_term isn't used there (instead term is).
-
-%type stop_term {Query *}
-%destructor stop_term {delete $$;}
-
-stop_term(T) ::= TERM(U). {
- if (state->is_stopword(U)) {
- T = NULL;
- state->add_to_stoplist(U);
- } else {
- T = new Query(U->get_query_with_auto_synonyms());
- }
- delete U;
-}
-
-stop_term(T) ::= compound_term(U). {
- T = U;
-}
-
-// term - A term or a compound_term.
-
-%type term {Query *}
-%destructor term {delete $$;}
-
-term(T) ::= TERM(U). {
- T = new Query(U->get_query_with_auto_synonyms());
- delete U;
-}
-
-term(T) ::= compound_term(U). {
- T = U;
-}
-
-// compound_term - A WILD_TERM, a quoted phrase (with or without prefix), a
-// phrased_term, group, near_expr, adj_expr, or a bracketed subexpression (with
-// or without prefix).
-
-%type compound_term {Query *}
-%destructor compound_term {delete $$;}
-
-compound_term(T) ::= WILD_TERM(U).
- { T = U->as_wildcarded_query(state); }
-
-compound_term(T) ::= PARTIAL_TERM(U).
- { T = U->as_partial_query(state); }
-
-compound_term(T) ::= QUOTE phrase(P) QUOTE.
- { T = P->as_phrase_query(); }
-
-compound_term(T) ::= phrased_term(P).
- { T = P->as_phrase_query(); }
-
-compound_term(T) ::= group(P). {
- T = P->as_group(state);
-}
-
-compound_term(T) ::= near_expr(P).
- { T = P->as_near_query(); }
-
-compound_term(T) ::= adj_expr(P).
- { T = P->as_adj_query(); }
-
-compound_term(T) ::= BRA expr(E) KET.
- { T = E; }
-
-compound_term(T) ::= SYNONYM TERM(U). {
- T = new Query(U->get_query_with_synonyms());
- delete U;
-}
-
-// phrase - The "inside the quotes" part of a double-quoted phrase.
-
-%type phrase {TermList *}
-
-%destructor phrase {$$->destroy();}
-
-phrase(P) ::= TERM(T). {
- P = new TermList;
- P->add_positional_term(T);
-}
-
-phrase(P) ::= phrase(Q) TERM(T). {
- P = Q;
- P->add_positional_term(T);
-}
-
-// phrased_term - A phrased term works like a single term, but is actually
-// 2 or more terms linked together into a phrase by punctuation. There must be
-// at least 2 terms in order to be able to have punctuation between the terms!
-
-%type phrased_term {TermList *}
-%destructor phrased_term {$$->destroy();}
-
-phrased_term(P) ::= TERM(T) PHR_TERM(U). {
- P = new TermList;
- P->add_positional_term(T);
- P->add_positional_term(U);
-}
-
-phrased_term(P) ::= phrased_term(Q) PHR_TERM(T). {
- P = Q;
- P->add_positional_term(T);
-}
-
-// group - A group of terms separated only by whitespace - candidates for
-// multi-term synonyms.
-
-%type group {TermGroup *}
-%destructor group {$$->destroy();}
-
-group(P) ::= TERM(T) GROUP_TERM(U). {
- P = new TermGroup;
- P->add_term(T);
- P->add_term(U);
-}
-
-group(P) ::= group(Q) GROUP_TERM(T). {
- P = Q;
- P->add_term(T);
-}
-
-// near_expr - 2 or more terms with NEAR in between. There must be at least 2
-// terms in order for there to be any NEAR operators!
-
-%type near_expr {TermList *}
-%destructor near_expr {$$->destroy();}
-
-near_expr(P) ::= TERM(T) NEAR(N) TERM(U). {
- P = new TermList;
- P->add_positional_term(T);
- P->add_positional_term(U);
- if (N) {
- P->adjust_window(N->get_termpos());
- delete N;
- }
-}
-
-near_expr(P) ::= near_expr(Q) NEAR(N) TERM(T). {
- P = Q;
- P->add_positional_term(T);
- if (N) {
- P->adjust_window(N->get_termpos());
- delete N;
- }
-}
-
-// adj_expr - 2 or more terms with ADJ in between. There must be at least 2
-// terms in order for there to be any ADJ operators!
-
-%type adj_expr {TermList *}
-%destructor adj_expr {$$->destroy();}
-
-adj_expr(P) ::= TERM(T) ADJ(N) TERM(U). {
- P = new TermList;
- P->add_positional_term(T);
- P->add_positional_term(U);
- if (N) {
- P->adjust_window(N->get_termpos());
- delete N;
- }
-}
-
-adj_expr(P) ::= adj_expr(Q) ADJ(N) TERM(T). {
- P = Q;
- P->add_positional_term(T);
- if (N) {
- P->adjust_window(N->get_termpos());
- delete N;
- }
-}
-
-// Select yacc syntax highlighting in vim editor: vim: syntax=yacc
-// (lemon syntax colouring isn't supplied by default; yacc does an OK job).