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: -

- -
    -
  1. -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. -

  2. - -
  3. -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. -

  4. - -
  5. -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. -

  6. - -
  7. -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. -

  8. -
- -

- - - - - -
-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; istate = 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: -**

-** -** 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: -** -*/ -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).