diff --git a/td/generate/tl-parser/CMakeLists.txt b/td/generate/tl-parser/CMakeLists.txt new file mode 100644 index 000000000..05c3ca016 --- /dev/null +++ b/td/generate/tl-parser/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0 FATAL_ERROR) + +project(tl-parser LANGUAGES C) + +set(SOURCES crc32.h crc32.c tlc.c tl-parser.c tl-parser.h tl-parser-tree.h tl-tl.h portable_endian.h) + +if (WIN32) + add_definitions("-D_CRT_SECURE_NO_WARNINGS") + list(APPEND SOURCES wgetopt.c wgetopt.h) + if (MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8 /wd4101 /wd4244") + endif() +endif() + +add_executable(${PROJECT_NAME} ${SOURCES}) + +if (NOT WIN32) + target_link_libraries(${PROJECT_NAME} m) +endif() diff --git a/td/generate/tl-parser/LICENSE b/td/generate/tl-parser/LICENSE new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/td/generate/tl-parser/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, 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 Lesser 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 Street, 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 Lesser General +Public License instead of this License. diff --git a/td/generate/tl-parser/crc32.c b/td/generate/tl-parser/crc32.c new file mode 100644 index 000000000..b7e02181b --- /dev/null +++ b/td/generate/tl-parser/crc32.c @@ -0,0 +1,345 @@ +/* + This file is part of VK/KittenPHP-DB-Engine Library. + + VK/KittenPHP-DB-Engine Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + VK/KittenPHP-DB-Engine Library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with VK/KittenPHP-DB-Engine Library. If not, see . + + Copyright 2009-2012 Vkontakte Ltd + 2009-2012 Nikolai Durov + 2009-2012 Andrei Lopatin + 2012 Anton Maydell +*/ + +#include +#include +#include + +#include "crc32.h" + +unsigned int crc32_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +unsigned int crc32_table2[256] = +{ + 0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, + 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, + 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, + 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, + 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, + 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, + 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, + 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, + 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, + 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, + 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, + 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, + 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, + 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, + 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, + 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, + 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, + 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, + 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, + 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, + 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, + 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, + 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, + 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, + 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, + 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, + 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, + 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, + 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, + 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, + 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, + 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, + 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, + 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, + 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, + 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, + 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, + 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, + 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, + 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, + 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, + 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, + 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, + 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, + 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, + 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, + 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, + 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, + 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, + 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, + 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, + 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72, +}; + +unsigned int crc32_table1[256] = +{ + 0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, + 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, + 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, + 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, + 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, + 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, + 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, + 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, + 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, + 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, + 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, + 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, + 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, + 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, + 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, + 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, + 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, + 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, + 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, + 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, + 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, + 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, + 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, + 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, + 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, + 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, + 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, + 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, + 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, + 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, + 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, + 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, + 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, + 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, + 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, + 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, + 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, + 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, + 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, + 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, + 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, + 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, + 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, + 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, + 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, + 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, + 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, + 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, + 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, + 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, + 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, + 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed, +}; + +unsigned int crc32_table0[256] = { + 0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, + 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, + 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, + 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, + 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, + 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, + 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, + 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, + 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, + 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, + 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, + 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, + 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, + 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, + 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, + 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, + 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, + 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, + 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, + 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, + 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, + 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, + 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, + 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, + 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, + 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, + 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, + 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, + 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, + 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, + 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, + 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, + 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, + 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, + 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, + 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, + 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, + 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, + 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, + 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, + 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, + 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, + 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, + 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, + 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, + 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, + 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, + 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, + 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, + 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, + 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, + 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1, +}; + +static unsigned int crc32_partial (const void *data, int len, unsigned crc) { + const int *p = (const int *) data; + int x; +#define DO_ONE(v) crc ^= v; crc = crc32_table0[crc & 0xff] ^ crc32_table1[(crc & 0xff00) >> 8] ^ crc32_table2[(crc & 0xff0000) >> 16] ^ crc32_table[crc >> 24]; +#define DO_FOUR(p) DO_ONE((p)[0]); DO_ONE((p)[1]); DO_ONE((p)[2]); DO_ONE((p)[3]); + + for (x = (len >> 5); x > 0; x--) { + DO_FOUR (p); + DO_FOUR (p + 4); + p += 8; + } + if (len & 16) { + DO_FOUR (p); + p += 4; + } + if (len & 8) { + DO_ONE (p[0]); + DO_ONE (p[1]); + p += 2; + } + if (len & 4) { + DO_ONE (*p++); + } + /* + for (x = (len >> 2) & 7; x > 0; x--) { + DO_ONE (*p++); + } + */ +#undef DO_ONE +#undef DO_FOUR + const char *q = (const char *) p; + if (len & 2) { + crc = crc32_table[(crc ^ q[0]) & 0xff] ^ (crc >> 8); + crc = crc32_table[(crc ^ q[1]) & 0xff] ^ (crc >> 8); + q += 2; + } + if (len & 1) { + crc = crc32_table[(crc ^ *q++) & 0xff] ^ (crc >> 8); + } + return crc; +} + +unsigned int compute_crc32 (const void *data, int len) { + return crc32_partial (data, len, -1) ^ -1; +} + diff --git a/td/generate/tl-parser/crc32.h b/td/generate/tl-parser/crc32.h new file mode 100644 index 000000000..b461784b3 --- /dev/null +++ b/td/generate/tl-parser/crc32.h @@ -0,0 +1,37 @@ +/* + This file is part of VK/KittenPHP-DB-Engine Library. + + VK/KittenPHP-DB-Engine Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + VK/KittenPHP-DB-Engine Library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with VK/KittenPHP-DB-Engine Library. If not, see . + + Copyright 2009-2012 Vkontakte Ltd + 2009-2012 Nikolai Durov + 2009-2012 Andrei Lopatin + 2012 Anton Maydell +*/ + +#ifndef __CRC32_H__ +#define __CRC32_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned int compute_crc32 (const void *data, int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/td/generate/tl-parser/portable_endian.h b/td/generate/tl-parser/portable_endian.h new file mode 100644 index 000000000..9f6d2f41c --- /dev/null +++ b/td/generate/tl-parser/portable_endian.h @@ -0,0 +1,124 @@ +// "License": Public Domain +// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. +// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to +// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it +// an example on how to get the endian conversion functions on different platforms. + +/* Originally cloned from https://gist.github.com/PkmX/63dd23f28ba885be53a5 + * Commit was: 1eca2ab34f2301b9641aa73d1016b951fff3fc39 + * Re-published at https://github.com/BenWiederhake/portable-endian.h to provide a means to submit patches and report issues. */ + +#ifndef PORTABLE_ENDIAN_H__ +#define PORTABLE_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +# define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) + +# include + +#elif defined(__APPLE__) + +# include + +# define htobe16(x) OSSwapHostToBigInt16(x) +# define htole16(x) OSSwapHostToLittleInt16(x) +# define be16toh(x) OSSwapBigToHostInt16(x) +# define le16toh(x) OSSwapLittleToHostInt16(x) + +# define htobe32(x) OSSwapHostToBigInt32(x) +# define htole32(x) OSSwapHostToLittleInt32(x) +# define be32toh(x) OSSwapBigToHostInt32(x) +# define le32toh(x) OSSwapLittleToHostInt32(x) + +# define htobe64(x) OSSwapHostToBigInt64(x) +# define htole64(x) OSSwapHostToLittleInt64(x) +# define be64toh(x) OSSwapBigToHostInt64(x) +# define le64toh(x) OSSwapLittleToHostInt64(x) + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +# include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + +# include + +# define be16toh(x) betoh16(x) +# define le16toh(x) letoh16(x) + +# define be32toh(x) betoh32(x) +# define le32toh(x) letoh32(x) + +# define be64toh(x) betoh64(x) +# define le64toh(x) letoh64(x) + +#elif defined(__WINDOWS__) + +# include +#ifdef __MINGW32__ +# include +#endif + +# if BYTE_ORDER == LITTLE_ENDIAN + +# define htobe16(x) htons(x) +# define htole16(x) (x) +# define be16toh(x) ntohs(x) +# define le16toh(x) (x) + +# define htobe32(x) htonl(x) +# define htole32(x) (x) +# define be32toh(x) ntohl(x) +# define le32toh(x) (x) + +# define htobe64(x) htonll(x) +# define htole64(x) (x) +# define be64toh(x) ntohll(x) +# define le64toh(x) (x) + +# elif BYTE_ORDER == BIG_ENDIAN + + /* that would be xbox 360 */ +# define htobe16(x) (x) +# define htole16(x) __builtin_bswap16(x) +# define be16toh(x) (x) +# define le16toh(x) __builtin_bswap16(x) + +# define htobe32(x) (x) +# define htole32(x) __builtin_bswap32(x) +# define be32toh(x) (x) +# define le32toh(x) __builtin_bswap32(x) + +# define htobe64(x) (x) +# define htole64(x) __builtin_bswap64(x) +# define be64toh(x) (x) +# define le64toh(x) __builtin_bswap64(x) + +# else + +# error byte order not supported + +# endif + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#else + +# error platform not supported + +#endif + +#endif diff --git a/td/generate/tl-parser/tl-parser-tree.h b/td/generate/tl-parser/tl-parser-tree.h new file mode 100644 index 000000000..fba7c6752 --- /dev/null +++ b/td/generate/tl-parser/tl-parser-tree.h @@ -0,0 +1,178 @@ +/* + This file is part of tgl-library + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Copyright Vitaly Valtman 2013-2014 +*/ +#ifndef __TREE_H__ +#define __TREE_H__ +#include + +#include +#include + +#pragma pack(push,4) +#define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ +struct tree_ ## X_NAME { \ + struct tree_ ## X_NAME *left, *right;\ + X_TYPE x;\ + int y;\ +};\ +\ +static struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\ + struct tree_ ## X_NAME *T = malloc (sizeof (*T));\ + T->x = x;\ + T->y = y;\ + T->left = T->right = 0;\ + return T;\ +}\ +\ +static void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\ + free (T);\ +}\ +\ +static void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\ + if (!T) {\ + *L = *R = 0;\ + } else {\ + int c = X_CMP (x, T->x);\ + if (c < 0) {\ + tree_split_ ## X_NAME (T->left, x, L, &T->left);\ + *R = T;\ + } else {\ + tree_split_ ## X_NAME (T->right, x, &T->right, R);\ + *L = T;\ + }\ + }\ +}\ +\ +static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result,unused));\ +static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\ + if (!T) {\ + return new_tree_node_ ## X_NAME (x, y);\ + } else {\ + if (y > T->y) {\ + struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\ + tree_split_ ## X_NAME (T, x, &N->left, &N->right);\ + return N;\ + } else {\ + int c = X_CMP (x, T->x);\ + assert (c);\ + if (c < 0) { \ + T->left = tree_insert_ ## X_NAME (T->left, x, y);\ + } else { \ + T->right = tree_insert_ ## X_NAME (T->right, x, y);\ + } \ + return T; \ + }\ + }\ +}\ +\ +static struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\ + if (!L || !R) {\ + return L ? L : R;\ + } else {\ + if (L->y > R->y) {\ + L->right = tree_merge_ ## X_NAME (L->right, R);\ + return L;\ + } else {\ + R->left = tree_merge_ ## X_NAME (L, R->left);\ + return R;\ + }\ + }\ +}\ +\ +static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result,unused));\ +static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ + assert (T);\ + int c = X_CMP (x, T->x);\ + if (!c) {\ + struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\ + delete_tree_node_ ## X_NAME (T);\ + return N;\ + } else {\ + if (c < 0) { \ + T->left = tree_delete_ ## X_NAME (T->left, x); \ + } else { \ + T->right = tree_delete_ ## X_NAME (T->right, x); \ + } \ + return T; \ + }\ +}\ +\ +static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *t) __attribute__ ((unused));\ +static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\ + if (!T) { return X_UNSET; } \ + while (T->left) { T = T->left; }\ + return T->x; \ +} \ +\ +static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((unused));\ +static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ + int c;\ + while (T && (c = X_CMP (x, T->x))) {\ + T = (c < 0 ? T->left : T->right);\ + }\ + return T ? T->x : X_UNSET;\ +}\ +\ +static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) __attribute__ ((unused));\ +static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\ + if (!T) { return; } \ + tree_act_ ## X_NAME (T->left, act); \ + act (T->x); \ + tree_act_ ## X_NAME (T->right, act); \ +}\ +\ +static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) __attribute__ ((unused));\ +static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) {\ + if (!T) { return; } \ + tree_act_ex_ ## X_NAME (T->left, act, extra); \ + act (T->x, extra); \ + tree_act_ex_ ## X_NAME (T->right, act, extra); \ +}\ +\ +static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ +static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \ + if (!T) { return 0; }\ + return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \ +}\ +static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ +static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \ + if (!T) { return; }\ + if (T->left) { \ + assert (T->left->y <= T->y);\ + assert (X_CMP (T->left->x, T->x) < 0); \ + }\ + if (T->right) { \ + assert (T->right->y <= T->y);\ + assert (X_CMP (T->right->x, T->x) > 0); \ + }\ + tree_check_ ## X_NAME (T->left); \ + tree_check_ ## X_NAME (T->right); \ +}\ +static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ +static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) { \ + if (!T) { return 0; }\ + tree_clear_ ## X_NAME (T->left); \ + tree_clear_ ## X_NAME (T->right); \ + delete_tree_node_ ## X_NAME (T); \ + return 0; \ +} \ + +#define int_cmp(a,b) ((a) - (b)) +#pragma pack(pop) +#endif diff --git a/td/generate/tl-parser/tl-parser.c b/td/generate/tl-parser/tl-parser.c new file mode 100644 index 000000000..66276ba01 --- /dev/null +++ b/td/generate/tl-parser/tl-parser.c @@ -0,0 +1,3078 @@ +/* + This file is part of tl-parser + + tl-parser 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. + + tl-parser 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 tl-parser. If not, see . + + Copyright Vitaly Valtman 2014 + + It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) + Copyright 2012-2013 Vkontakte Ltd + 2012-2013 Vitaliy Valtman + +*/ + +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "portable_endian.h" +#include "tl-parser-tree.h" +#include "tl-parser.h" +#include "crc32.h" +#include "tl-tl.h" + +extern int verbosity; +extern int schema_version; +extern int output_expressions; + + +int total_types_num; +int total_constructors_num; +int total_functions_num; + + +/*char *tstrdup (const char *s) { + assert (s); + char *r = talloc (strlen (s) + 1); + memcpy (r, s, strlen (s) + 1); + return r; +}*/ + +#define talloc(a) malloc(a) +#define tfree(a,b) free (a) +#define talloc0(a) calloc(a,1) +#define tstrdup(a) strdup(a) + +typedef char error_int_must_be_4_byte[(sizeof (int) == 4) ? 1 : -1]; +typedef char error_long_long_must_be_8_byte[(sizeof (long long) == 8) ? 1 : -1]; + +char curch; +struct parse parse; + +struct tree *tree; + +struct tree *tree_alloc (void) { + struct tree *T = talloc (sizeof (*T)); + assert (T); + memset (T, 0, sizeof (*T)); + return T; +} + +void tree_add_child (struct tree *P, struct tree *C) { + if (P->nc == P->size) { + void **t = talloc (sizeof (void *) * (++P->size)); + memcpy (t, P->c, sizeof (void *) * (P->size - 1)); + if (P->c) { + tfree (P->c, sizeof (void *) * (P->size - 1)); + } + P->c = (void *)t; + assert (P->c); + } + P->c[P->nc ++] = C; +} + +void tree_delete (struct tree *T) { + assert (T); + int i; + for (i = 0; i < T->nc; i++) { + assert (T->c[i]); + tree_delete (T->c[i]); + } + if (T->c) { + tfree (T->c, sizeof (void *) * T->nc); + } + tfree (T, sizeof (*T)); +} + +void tree_del_child (struct tree *P) { + assert (P->nc); + tree_delete (P->c[--P->nc]); +} + + +char nextch (void) { + if (parse.pos < parse.len - 1) { + curch = parse.text[++parse.pos]; + } else { + curch = 0; + } + if (curch == 10) { + parse.line ++; + parse.line_pos = 0; + } else { + if (curch) { + parse.line_pos ++; + } + } + return curch; +} + + +struct parse save_parse (void) { + return parse; +} + +void load_parse (struct parse _parse) { + parse = _parse; + curch = parse.pos > parse.len ? 0: parse.text[parse.pos] ; +} + +int is_whitespace (char c) { + return (c <= 32); +} + +int is_uletter (char c) { + return (c >= 'A' && c <= 'Z'); +} + +int is_lletter (char c) { + return (c >= 'a' && c <= 'z'); +} + +int is_letter (char c) { + return is_uletter (c) || is_lletter (c); +} + +int is_digit (char c) { + return (c >= '0' && c <= '9'); +} + +int is_hexdigit (char c) { + return is_digit (c) || (c >= 'a' && c <= 'f'); +} + +int is_ident_char (char c) { + return is_digit (c) || is_letter (c) || c == '_'; +} + +int last_error_pos; +int last_error_line; +int last_error_line_pos; +char *last_error; + +void parse_error (const char *e) { + if (parse.pos > last_error_pos) { + last_error_pos = parse.pos; + last_error_line = parse.line; + last_error_line_pos = parse.line_pos; + if (last_error) { + tfree (last_error, strlen (last_error) + 1); + } + last_error = tstrdup (e); + } +} + +void tl_print_parse_error (void) { + fprintf (stderr, "Error near line %d pos %d: `%s`\n", last_error_line + 1, last_error_line_pos + 1, last_error); +} + +char *parse_lex (void) { + while (1) { + while (curch && is_whitespace (curch)) { nextch (); } + if (curch == '/' && nextch () == '/') { + while (nextch () != 10); + nextch (); + } else { + break; + } + } + if (!curch) { + parse.lex.len = 0; + parse.lex.type = lex_eof; + return (parse.lex.ptr = 0); + } + char *p = parse.text + parse.pos; + parse.lex.flags = 0; + switch (curch) { + case '-': + if (nextch () != '-' || nextch () != '-') { + parse_error ("Can not parse triple minus"); + parse.lex.type = lex_error; + return (parse.lex.ptr = (void *)-1); + } else { + parse.lex.len = 3; + parse.lex.type = lex_triple_minus; + nextch (); + return (parse.lex.ptr = p); + } + case ':': + case ';': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '=': + case '#': + case '?': + case '%': + case '<': + case '>': + case '+': + case ',': + case '*': + case '_': + case '!': + case '.': + nextch (); + parse.lex.len = 1; + parse.lex.type = lex_char; + return (parse.lex.ptr = p); + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + parse.lex.flags = 0; + if (is_uletter (curch)) { + while (is_ident_char (nextch ())); + parse.lex.len = parse.text + parse.pos - p; + parse.lex.ptr = p; + if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Final", 5)) { + parse.lex.type = lex_final; + } else if (parse.lex.len == 3 && !memcmp (parse.lex.ptr, "New", 3)) { + parse.lex.type = lex_new; + } else if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Empty", 5)) { + parse.lex.type = lex_empty; + } else { + parse.lex.type = lex_uc_ident; + } + return (parse.lex.ptr = p); + } + while (is_ident_char (nextch ())); + if (curch == '.' && !is_letter (parse.text[parse.pos + 1])) { + parse.lex.len = parse.text + parse.pos - p; + parse.lex.type = lex_lc_ident; + return (parse.lex.ptr = p); + } + while (curch == '.') { + parse.lex.flags |= 1; + nextch (); + if (is_uletter (curch)) { + while (is_ident_char (nextch ())); + parse.lex.len = parse.text + parse.pos - p; + parse.lex.type = lex_uc_ident; + return (parse.lex.ptr = p); + } + if (is_lletter (curch)) { + while (is_ident_char (nextch ())); + } else { + parse_error ("Expected letter"); + parse.lex.type = lex_error; + return (parse.lex.ptr = (void *)-1); + } + } + if (curch == '#') { + parse.lex.flags |= 2; + int i; + int ok = 1; + for (i = 0; i < 8; i++) { + if (!is_hexdigit (nextch())) { + if (curch == ' ' && i >= 5) { + ok = 2; + break; + } else { + parse_error ("Hex digit expected"); + parse.lex.type = lex_error; + return (parse.lex.ptr = (void *)-1); + } + } + } + if (ok == 1) { + nextch (); + } + } + parse.lex.len = parse.text + parse.pos - p; + parse.lex.type = lex_lc_ident; + return (parse.lex.ptr = p); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + while (is_digit (nextch ())); + parse.lex.len = parse.text + parse.pos - p; + parse.lex.type = lex_num; + return (parse.lex.ptr = p); + default: + parse_error ("Unknown lexem"); + parse.lex.type = lex_error; + return (parse.lex.ptr = (void *)-1); + } + +} + +int expect (char *s) { + if (!parse.lex.ptr || parse.lex.ptr == (void *)-1 || parse.lex.type == lex_error || parse.lex.type == lex_none || parse.lex.len != (int)strlen (s) || memcmp (s, parse.lex.ptr, parse.lex.len)) { + static char buf[1000]; + sprintf (buf, "Expected %s", s); + parse_error (buf); + return -1; + } else { + parse_lex (); + } + return 1; +} + +struct parse *tl_init_parse_file (const char *fname) { + FILE *f = fopen (fname, "rb"); + if (f == NULL) { + fprintf (stderr, "Failed to open the input file.\n"); + return NULL; + } + if (fseek (f, 0, SEEK_END) != 0) { + fprintf (stderr, "Can't seek to the end of the input file.\n"); + return NULL; + } + long size = ftell (f); + if (size <= 0 || size > INT_MAX) { + fprintf (stderr, "Size is %ld. Too small or too big.\n", size); + return NULL; + } + fseek (f, 0, SEEK_SET); + + static struct parse save; + save.text = talloc ((size_t)size); + save.len = fread (save.text, 1, (size_t)size, f); + assert (save.len == size); + fclose (f); + save.pos = 0; + save.line = 0; + save.line_pos = 0; + save.lex.ptr = save.text; + save.lex.len = 0; + save.lex.type = lex_none; + return &save; +} + +#define PARSE_INIT(_type) struct parse save = save_parse (); struct tree *T = tree_alloc (); T->type = (_type); T->lex_line = parse.line; T->lex_line_pos = parse.line_pos; struct tree *S __attribute__ ((unused)); +#define PARSE_FAIL load_parse (save); tree_delete (T); return 0; +#define PARSE_OK return T; +#define PARSE_TRY_PES(x) if (!(S = x ())) { PARSE_FAIL; } { tree_add_child (T, S); } +#define PARSE_TRY_OPT(x) if ((S = x ())) { tree_add_child (T, S); PARSE_OK } +#define PARSE_TRY(x) S = x (); +#define PARSE_ADD(_type) S = tree_alloc (); S->type = _type; tree_add_child (T, S); +#define EXPECT(s) if (expect (s) < 0) { PARSE_FAIL; } +#define LEX_CHAR(c) (parse.lex.type == lex_char && *parse.lex.ptr == c) +struct tree *parse_args (void); +struct tree *parse_expr (void); + +struct tree *parse_boxed_type_ident (void) { + PARSE_INIT (type_boxed_type_ident); + if (parse.lex.type != lex_uc_ident) { + parse_error ("Can not parse boxed type"); + PARSE_FAIL; + } else { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } +} + +struct tree *parse_full_combinator_id (void) { + PARSE_INIT (type_full_combinator_id); + if (parse.lex.type == lex_lc_ident || LEX_CHAR('_')) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse full combinator id"); + PARSE_FAIL; + } +} + +struct tree *parse_combinator_id (void) { + PARSE_INIT (type_combinator_id); + if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse combinator id"); + PARSE_FAIL; + } +} + +struct tree *parse_var_ident (void) { + PARSE_INIT (type_var_ident); + if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident) && !(parse.lex.flags & 3)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse var ident"); + PARSE_FAIL; + } +} + +struct tree *parse_var_ident_opt (void) { + PARSE_INIT (type_var_ident_opt); + if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident)&& !(parse.lex.flags & 3)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else if (LEX_CHAR ('_')) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse var ident opt"); + PARSE_FAIL; + } +} + +struct tree *parse_nat_const (void) { + PARSE_INIT (type_nat_const); + if (parse.lex.type == lex_num) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse nat const"); + PARSE_FAIL; + } +} + +struct tree *parse_type_ident (void) { + PARSE_INIT (type_type_ident); + if (parse.lex.type == lex_uc_ident && !(parse.lex.flags & 2)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else if (LEX_CHAR ('#')) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse type ident"); + PARSE_FAIL; + } +} + +struct tree *parse_term (void) { + PARSE_INIT (type_term); + while (LEX_CHAR ('%')) { + EXPECT ("%") + PARSE_ADD (type_percent); + } + if (LEX_CHAR ('(')) { + EXPECT ("("); + PARSE_TRY_PES (parse_expr); + EXPECT (")"); + PARSE_OK; + } + PARSE_TRY (parse_type_ident); + if (S) { + tree_add_child (T, S); + if (LEX_CHAR ('<')) { + EXPECT ("<"); + while (1) { + PARSE_TRY_PES (parse_expr); + if (LEX_CHAR ('>')) { break; } + EXPECT (","); + } + EXPECT (">"); + } + PARSE_OK; + } + PARSE_TRY_OPT (parse_type_ident); + PARSE_TRY_OPT (parse_var_ident); + PARSE_TRY_OPT (parse_nat_const); + PARSE_FAIL; +} + +struct tree *parse_nat_term (void) { + PARSE_INIT (type_nat_term); + PARSE_TRY_PES (parse_term); + PARSE_OK; +} + +struct tree *parse_subexpr (void) { + PARSE_INIT (type_subexpr); + int was_term = 0; + int cc = 0; + + while (1) { + PARSE_TRY (parse_nat_const); + if (S) { + tree_add_child (T, S); + } else if (!was_term) { + was_term = 1; + PARSE_TRY (parse_term); + if (S) { + tree_add_child (T, S); + } else { + break; + } + } + cc ++; + if (!LEX_CHAR ('+')) { + break; + } + EXPECT ("+"); + } + if (!cc) { + PARSE_FAIL; + } else { + PARSE_OK; + } +} + +struct tree *parse_expr (void) { + PARSE_INIT (type_expr); + int cc = 0; + while (1) { + PARSE_TRY (parse_subexpr); + if (S) { + tree_add_child (T, S); + cc ++; + } else { + if (cc < 1) { PARSE_FAIL; } + else { PARSE_OK; } + } + } +} + + + +struct tree *parse_final_empty (void) { + PARSE_INIT (type_final_empty); + EXPECT ("Empty"); + PARSE_TRY_PES (parse_boxed_type_ident); + PARSE_OK; +} + +struct tree *parse_final_new (void) { + PARSE_INIT (type_final_new); + EXPECT ("New"); + PARSE_TRY_PES (parse_boxed_type_ident); + PARSE_OK; +} + +struct tree *parse_final_final (void) { + PARSE_INIT (type_final_final); + EXPECT ("Final"); + PARSE_TRY_PES (parse_boxed_type_ident); + PARSE_OK; +} + +struct tree *parse_partial_comb_app_decl (void) { + PARSE_INIT (type_partial_comb_app_decl); + PARSE_TRY_PES (parse_combinator_id); + while (1) { + PARSE_TRY_PES (parse_subexpr); + if (LEX_CHAR (';')) { break; } + } + PARSE_OK; +} + +struct tree *parse_partial_type_app_decl (void) { + PARSE_INIT (type_partial_type_app_decl); + PARSE_TRY_PES (parse_boxed_type_ident); + if (LEX_CHAR ('<')) { + EXPECT ("<"); + while (1) { + PARSE_TRY_PES (parse_expr); + if (LEX_CHAR ('>')) { break; } + EXPECT (","); + } + EXPECT (">"); + PARSE_OK; + } else { + while (1) { + PARSE_TRY_PES (parse_subexpr); + if (LEX_CHAR (';')) { break; } + } + PARSE_OK; + } +} + + + + +struct tree *parse_multiplicity (void) { + PARSE_INIT (type_multiplicity); + PARSE_TRY_PES (parse_nat_term); + PARSE_OK; +} + + +struct tree *parse_type_term (void) { + PARSE_INIT (type_type_term); + PARSE_TRY_PES (parse_term); + PARSE_OK; +} + +struct tree *parse_optional_arg_def (void) { + PARSE_INIT (type_optional_arg_def); + PARSE_TRY_PES (parse_var_ident); + EXPECT ("."); + PARSE_TRY_PES (parse_nat_const); + EXPECT ("?"); + PARSE_OK; +} + +struct tree *parse_args4 (void) { + PARSE_INIT (type_args4); + struct parse so = save_parse (); + PARSE_TRY (parse_optional_arg_def); + if (S) { + tree_add_child (T, S); + } else { + load_parse (so); + } + if (LEX_CHAR ('!')) { + PARSE_ADD (type_exclam); + EXPECT ("!"); + } + PARSE_TRY_PES (parse_type_term); + PARSE_OK; +} + +struct tree *parse_args3 (void) { + PARSE_INIT (type_args3); + PARSE_TRY_PES (parse_var_ident_opt); + EXPECT (":"); + struct parse so = save_parse (); + PARSE_TRY (parse_optional_arg_def); + if (S) { + tree_add_child (T, S); + } else { + load_parse (so); + } + if (LEX_CHAR ('!')) { + PARSE_ADD (type_exclam); + EXPECT ("!"); + } + PARSE_TRY_PES (parse_type_term); + PARSE_OK; +} + +struct tree *parse_args2 (void) { + PARSE_INIT (type_args2); + PARSE_TRY (parse_var_ident_opt); + if (S && LEX_CHAR (':')) { + tree_add_child (T, S); + EXPECT (":"); + } else { + load_parse (save); + } + struct parse so = save_parse (); + PARSE_TRY (parse_optional_arg_def); + if (S) { + tree_add_child (T, S); + } else { + load_parse (so); + } + struct parse save2 = save_parse (); + PARSE_TRY (parse_multiplicity); + if (S && LEX_CHAR ('*')) { + tree_add_child (T, S); + EXPECT ("*"); + } else { + load_parse (save2); + } + EXPECT ("["); + while (1) { + if (LEX_CHAR (']')) { break; } + PARSE_TRY_PES (parse_args); + } + EXPECT ("]"); + PARSE_OK; +} + +struct tree *parse_args1 (void) { + PARSE_INIT (type_args1); + EXPECT ("("); + while (1) { + PARSE_TRY_PES (parse_var_ident_opt); + if (LEX_CHAR(':')) { break; } + } + EXPECT (":"); + struct parse so = save_parse (); + PARSE_TRY (parse_optional_arg_def); + if (S) { + tree_add_child (T, S); + } else { + load_parse (so); + } + if (LEX_CHAR ('!')) { + PARSE_ADD (type_exclam); + EXPECT ("!"); + } + PARSE_TRY_PES (parse_type_term); + EXPECT (")"); + PARSE_OK; +} + +struct tree *parse_args (void) { + PARSE_INIT (type_args); + PARSE_TRY_OPT (parse_args1); + PARSE_TRY_OPT (parse_args2); + PARSE_TRY_OPT (parse_args3); + PARSE_TRY_OPT (parse_args4); + PARSE_FAIL; +} + +struct tree *parse_opt_args (void) { + PARSE_INIT (type_opt_args); + while (1) { + PARSE_TRY_PES (parse_var_ident); + if (parse.lex.type == lex_char && *parse.lex.ptr == ':') { break;} + } + EXPECT (":"); + PARSE_TRY_PES (parse_type_term); + PARSE_OK; +} + +struct tree *parse_final_decl (void) { + PARSE_INIT (type_final_decl); + PARSE_TRY_OPT (parse_final_new); + PARSE_TRY_OPT (parse_final_final); + PARSE_TRY_OPT (parse_final_empty); + PARSE_FAIL; +} + +struct tree *parse_partial_app_decl (void) { + PARSE_INIT (type_partial_app_decl); + PARSE_TRY_OPT (parse_partial_type_app_decl); + PARSE_TRY_OPT (parse_partial_comb_app_decl); + PARSE_FAIL; +} + +struct tree *parse_result_type (void) { + PARSE_INIT (type_result_type); + PARSE_TRY_PES (parse_boxed_type_ident); + if (LEX_CHAR ('<')) { + EXPECT ("<"); + while (1) { + PARSE_TRY_PES (parse_expr); + if (LEX_CHAR ('>')) { break; } + EXPECT (","); + } + EXPECT (">"); + PARSE_OK; + } else { + while (1) { + if (LEX_CHAR (';')) { PARSE_OK; } + PARSE_TRY_PES (parse_subexpr); + } + } +} + +struct tree *parse_combinator_decl (void) { + PARSE_INIT (type_combinator_decl); + PARSE_TRY_PES (parse_full_combinator_id) + while (1) { + if (LEX_CHAR ('{')) { + parse_lex (); + PARSE_TRY_PES (parse_opt_args); + EXPECT ("}"); + } else { + break; + } + } + while (1) { + if (LEX_CHAR ('=')) { break; } + PARSE_TRY_PES (parse_args); + } + EXPECT ("="); + PARSE_ADD (type_equals); + + PARSE_TRY_PES (parse_result_type); + PARSE_OK; +} + +struct tree *parse_builtin_combinator_decl (void) { + PARSE_INIT (type_builtin_combinator_decl); + PARSE_TRY_PES (parse_full_combinator_id) + EXPECT ("?"); + EXPECT ("="); + PARSE_TRY_PES (parse_boxed_type_ident); + PARSE_OK; +} + +struct tree *parse_declaration (void) { + PARSE_INIT (type_declaration); + PARSE_TRY_OPT (parse_combinator_decl); + PARSE_TRY_OPT (parse_partial_app_decl); + PARSE_TRY_OPT (parse_final_decl); + PARSE_TRY_OPT (parse_builtin_combinator_decl); + PARSE_FAIL; +} + +struct tree *parse_constr_declarations (void) { + PARSE_INIT (type_constr_declarations); + if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; } + while (1) { + PARSE_TRY_PES (parse_declaration); + EXPECT (";"); + if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; } + } +} + +struct tree *parse_fun_declarations (void) { + PARSE_INIT (type_fun_declarations); + if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; } + while (1) { + PARSE_TRY_PES (parse_declaration); + EXPECT (";"); + if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; } + } +} + +struct tree *parse_program (void) { + PARSE_INIT (type_tl_program); + while (1) { + PARSE_TRY_PES (parse_constr_declarations); + if (parse.lex.type == lex_eof) { PARSE_OK; } + if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("functions") < 0 || expect ("---") < 0) { PARSE_FAIL; } + + PARSE_TRY_PES (parse_fun_declarations); + if (parse.lex.type == lex_eof) { PARSE_OK; } + if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("types") < 0 || expect ("---") < 0) { PARSE_FAIL; } + } +} + +struct tree *tl_parse_lex (struct parse *_parse) { + assert (_parse); + load_parse (*_parse); + if (parse.lex.type == lex_none) { + parse_lex (); + } + if (parse.lex.type == lex_error) { + return 0; + } + return parse_program (); +} + +int mystrcmp2 (const char *b, int len, const char *a) { + int c = strncmp (b, a, len); + return c ? a[len] ? -1 : 0 : c; +} + +char *mystrdup (const char *a, int len) { + char *z = talloc (len + 1); + memcpy (z, a, len); + z[len] = 0; + return z; +} + +struct tl_program *tl_program_cur; +#define TL_TRY_PES(x) if (!(x)) { return 0; } + +#define tl_type_cmp(a,b) (strcmp (a->id, b->id)) +DEFINE_TREE (tl_type,struct tl_type *,tl_type_cmp,0) +struct tree_tl_type *tl_type_tree; + +DEFINE_TREE (tl_constructor,struct tl_constructor *,tl_type_cmp,0) +struct tree_tl_constructor *tl_constructor_tree; +struct tree_tl_constructor *tl_function_tree; + +DEFINE_TREE (tl_var,struct tl_var *,tl_type_cmp,0) + +struct tl_var_value { + struct tl_combinator_tree *ptr; + struct tl_combinator_tree *val; + int num_val; +}; + +#define tl_var_value_cmp(a,b) (((char *)a.ptr) - ((char *)b.ptr)) +struct tl_var_value empty; +DEFINE_TREE (var_value, struct tl_var_value, tl_var_value_cmp, empty) +//tree_tl_var_t *tl_var_tree; + +DEFINE_TREE (tl_field,char *,strcmp, 0) +//tree_tl_field_t *tl_field_tree; +#define TL_FAIL return 0; +#define TL_INIT(x) struct tl_combinator_tree *x = 0; +#define TL_TRY(f,x) { struct tl_combinator_tree *_t = f; if (!_t) { TL_FAIL;} x = tl_union (x, _t); if (!x) { TL_FAIL; }} +#define TL_ERROR(...) fprintf (stderr, __VA_ARGS__); +#define TL_WARNING(...) fprintf (stderr, __VA_ARGS__); + +void tl_set_var_value (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value) { + struct tl_var_value t = {.ptr = var, .val = value, .num_val = 0}; + if (tree_lookup_var_value (*T, t).ptr) { + *T = tree_delete_var_value (*T, t); + } + *T = tree_insert_var_value (*T, t, lrand48 ()); +} + +void tl_set_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value, long long num_value) { + struct tl_var_value t = {.ptr = var, .val = value, .num_val = num_value}; + if (tree_lookup_var_value (*T, t).ptr) { + *T = tree_delete_var_value (*T, t); + } + *T = tree_insert_var_value (*T, t, lrand48 ()); +} + +struct tl_combinator_tree *tl_get_var_value (struct tree_var_value **T, struct tl_combinator_tree *var) { + struct tl_var_value t = {.ptr = var, .val = 0, .num_val = 0}; + struct tl_var_value r = tree_lookup_var_value (*T, t); + return r.ptr ? r.val : 0; +} + +int tl_get_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var) { + struct tl_var_value t = {.ptr = var, .val = 0}; + struct tl_var_value r = tree_lookup_var_value (*T, t); + return r.ptr ? r.num_val : 0; +} + +int namespace_level; + +struct tree_tl_var *vars[10]; +struct tree_tl_field *fields[10]; +struct tl_var *last_num_var[10]; + +int tl_is_type_name (const char *id, int len) { + if (len == 1 && *id == '#') { return 1;} + int ok = id[0] >= 'A' && id[0] <= 'Z'; + int i; + for (i = 0; i < len - 1; i++) if (id[i] == '.') { + ok = id[i + 1] >= 'A' && id[i + 1] <= 'Z'; + } + return ok; +} + +int tl_add_field (char *id) { + assert (namespace_level < 10); + assert (namespace_level >= 0); + if (tree_lookup_tl_field (fields[namespace_level], id)) { + return 0; + } + fields[namespace_level] = tree_insert_tl_field (fields[namespace_level], id, lrand48 ()); + return 1; +} + +void tl_clear_fields (void) { +// tree_act_tl_field (fields[namespace_level], (void *)free); + fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]); +} + +struct tl_var *tl_add_var (char *id, struct tl_combinator_tree *ptr, int type) { + struct tl_var *v = talloc (sizeof (*v)); + v->id = tstrdup (id); + v->type = type; + v->ptr = ptr; + v->flags = 0; + if (tree_lookup_tl_var (vars[namespace_level], v)) { + return 0; + } + vars[namespace_level] = tree_insert_tl_var (vars[namespace_level], v, lrand48 ()); + if (type) { + last_num_var[namespace_level] = v; + } + return v; +} + +void tl_del_var (struct tl_var *v) { +// free (v->id); + tfree (v, sizeof (*v)); +} + +void tl_clear_vars (void) { + tree_act_tl_var (vars[namespace_level], tl_del_var); + vars[namespace_level] = tree_clear_tl_var (vars[namespace_level]); + last_num_var[namespace_level] = 0; +} + +struct tl_var *tl_get_last_num_var (void) { + return last_num_var[namespace_level]; +} + +struct tl_var *tl_get_var (char *_id, int len) { + char *id = mystrdup (_id, len); + struct tl_var v = {.id = id}; + int i; + for (i = namespace_level; i >= 0; i--) { + struct tl_var *w = tree_lookup_tl_var (vars[i], &v); + if (w) { + tfree (id, len + 1); + return w; + } + } + tfree (id, len + 1); + return 0; +} + +void namespace_push (void) { + namespace_level ++; + assert (namespace_level < 10); + tl_clear_vars (); + tl_clear_fields (); +} + +void namespace_pop (void) { + namespace_level --; + assert (namespace_level >= 0); +} + +struct tl_type *tl_get_type (const char *_id, int len) { + char *id = mystrdup (_id, len); + struct tl_type _t = {.id = id}; + struct tl_type *r = tree_lookup_tl_type (tl_type_tree, &_t); + tfree (id, len + 1); + return r; +} + +struct tl_type *tl_add_type (const char *_id, int len, int params_num, long long params_types) { + char *id = talloc (len + 1); + memcpy (id, _id, len); + id[len] = 0; + struct tl_type _t = {.id = id}; + struct tl_type *_r = 0; + if ((_r = tree_lookup_tl_type (tl_type_tree, &_t))) { + tfree (id, len + 1); + if (params_num >= 0 && (_r->params_num != params_num || _r->params_types != params_types)) { + TL_ERROR ("Wrong params_num or types for type %s\n", _r->id); + return 0; + } + return _r; + } + struct tl_type *t = talloc (sizeof (*t)); + t->id = id; + t->print_id = tstrdup (t->id); + int i; + for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { + t->print_id[i] = '$'; + } + t->name = 0; + t->constructors_num = 0; + t->constructors = 0; + t->flags = 0; + t->real_id = 0; + if (params_num >= 0) { + assert (params_num <= 64); + t->params_num = params_num; + t->params_types = params_types; + } else { + t->flags |= 4; + t->params_num = -1; + } + tl_type_tree = tree_insert_tl_type (tl_type_tree, t, lrand48 ()); + total_types_num ++; + return t; +} + +void tl_add_type_param (struct tl_type *t, int x) { + assert (t->flags & 4); + assert (t->params_num <= 64); + if (x) { + t->params_types |= (1ull << (t->params_num ++)); + } else { + t->params_num ++; + } +} + +int tl_type_set_params (struct tl_type *t, int x, long long y) { + if (t->flags & 4) { + t->params_num = x; + t->params_types = y; + t->flags &= ~4; + } else { + if (t->params_num != x || t->params_types != y) { + fprintf (stderr, "Wrong num of params (type %s)\n", t->id); + return 0; + } + } + return 1; +} + +void tl_type_finalize (struct tl_type *t) { + t->flags &= ~4; +} + +struct tl_constructor *tl_get_constructor (const char *_id, int len) { + char *id = mystrdup (_id, len); + struct tl_constructor _t = {.id = id}; + struct tl_constructor *r = tree_lookup_tl_constructor (tl_constructor_tree, &_t); + tfree (id, len + 1); + return r; +} + +struct tl_constructor *tl_add_constructor (struct tl_type *a, const char *_id, int len, int force_magic) { + assert (a); + if (a->flags & 1) { + TL_ERROR ("New constructor for type `%s` after final statement\n", a->id); + return 0; + } + int x = 0; + while (x < len && (_id[x] != '#' || force_magic)) { x++; } + char *id = talloc (x + 1); + memcpy (id, _id, x); + id[x] = 0; + + unsigned magic = 0; + if (x < len) { + assert (len - x >= 6 && len - x <= 9); + int i; + for (i = 1; i < len - x; i++) { + magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10); + } + assert (magic && magic != (unsigned)-1); + } + + len = x; + if (*id != '_') { + struct tl_constructor _t = {.id = id}; + if (tree_lookup_tl_constructor (tl_constructor_tree, &_t)) { + TL_ERROR ("Duplicate constructor id `%s`\n", id); + tfree (id, len + 1); + return 0; + } + } else { + assert (len == 1); + } + + struct tl_constructor *t = talloc (sizeof (*t)); + t->type = a; + t->name = magic; + t->id = id; + t->print_id = tstrdup (id); + t->real_id = 0; + + int i; + for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { + t->print_id[i] = '$'; + } + + t->left = t->right = 0; + a->constructors = realloc (a->constructors, sizeof (void *) * (a->constructors_num + 1)); + assert (a->constructors); + a->constructors[a->constructors_num ++] = t; + if (*id != '_') { + tl_constructor_tree = tree_insert_tl_constructor (tl_constructor_tree, t, lrand48 ()); + } else { + a->flags |= FLAG_DEFAULT_CONSTRUCTOR; + } + total_constructors_num ++; + return t; +} + +struct tl_constructor *tl_get_function (const char *_id, int len) { + char *id = mystrdup (_id, len); + struct tl_constructor _t = {.id = id}; + struct tl_constructor *r = tree_lookup_tl_constructor (tl_function_tree, &_t); + tfree (id, len + 1); + return r; +} + +struct tl_constructor *tl_add_function (struct tl_type *a, const char *_id, int len, int force_magic) { +// assert (a); + int x = 0; + while (x < len && ((_id[x] != '#') || force_magic)) { x++; } + char *id = talloc (x + 1); + memcpy (id, _id, x); + id[x] = 0; + + unsigned magic = 0; + if (x < len) { + assert (len - x >= 6 && len - x <= 9); + int i; + for (i = 1; i < len - x; i++) { + magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10); + } + assert (magic && magic != (unsigned)-1); + } + + len = x; + + struct tl_constructor _t = {.id = id}; + if (tree_lookup_tl_constructor (tl_function_tree, &_t)) { + TL_ERROR ("Duplicate function id `%s`\n", id); + tfree (id, len + 1); + return 0; + } + + struct tl_constructor *t = talloc (sizeof (*t)); + t->type = a; + t->name = magic; + t->id = id; + t->print_id = tstrdup (id); + t->real_id = 0; + + int i; + for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { + t->print_id[i] = '$'; + } + + t->left = t->right = 0; + tl_function_tree = tree_insert_tl_constructor (tl_function_tree, t, lrand48 ()); + total_functions_num ++; + return t; +} + +static char buf[(1 << 20)]; +int buf_pos; + +struct tl_combinator_tree *alloc_ctree_node (void) { + struct tl_combinator_tree *T = talloc (sizeof (*T)); + assert (T); + memset (T, 0, sizeof (*T)); + return T; +} + +struct tl_combinator_tree *tl_tree_dup (struct tl_combinator_tree *T) { + if (!T) { return 0; } + struct tl_combinator_tree *S = talloc (sizeof (*S)); + memcpy (S, T, sizeof (*S)); + S->left = tl_tree_dup (T->left); + S->right = tl_tree_dup (T->right); + return S; +} + +struct tl_type *tl_tree_get_type (struct tl_combinator_tree *T) { + assert (T->type == type_type); + if (T->act == act_array) { return 0;} + while (T->left) { + T = T->left; + if (T->act == act_array) { return 0;} + assert (T->type == type_type); + } + assert (T->act == act_type || T->act == act_var || T->act == act_array); + return T->act == act_type ? T->data : 0; +} + +void tl_tree_set_len (struct tl_combinator_tree *T) { + TL_INIT (H); + H = T; + while (H->left) { + H->left->type_len = H->type_len + 1; + H = H->left; + } + assert (H->type == type_type); + struct tl_type *t = H->data; + assert (t); + assert (H->type_len == t->params_num); +} + +void tl_buf_reset (void) { + buf_pos = 0; +} + +void tl_buf_add_string (char *s, int len) { + if (len < 0) { len = strlen (s); } + buf[buf_pos ++] = ' '; + memcpy (buf + buf_pos, s, len); buf_pos += len; + buf[buf_pos] = 0; +} + +void tl_buf_add_string_nospace (char *s, int len) { + if (len < 0) { len = strlen (s); } +// if (buf_pos) { buf[buf_pos ++] = ' '; } + memcpy (buf + buf_pos, s, len); buf_pos += len; + buf[buf_pos] = 0; +} + +void tl_buf_add_string_q (char *s, int len, int x) { + if (x) { + tl_buf_add_string (s, len); + } else { + tl_buf_add_string_nospace (s, len); + } +} + + +void tl_buf_add_tree (struct tl_combinator_tree *T, int x) { + if (!T) { return; } + assert (T != (void *)-1l && T != (void *)-2l); + switch (T->act) { + case act_question_mark: + tl_buf_add_string_q ("?", -1, x); + return; + case act_type: + if ((T->flags & 1) && !(T->flags & 4)) { + tl_buf_add_string_q ("%", -1, x); + x = 0; + } + if (T->flags & 2) { + tl_buf_add_string_q ((char *)T->data, -1, x); + } else { + struct tl_type *t = T->data; + if (T->flags & 4) { + assert (t->constructors_num == 1); + tl_buf_add_string_q (t->constructors[0]->real_id ? t->constructors[0]->real_id : t->constructors[0]->id, -1, x); + } else { + tl_buf_add_string_q (t->real_id ? t->real_id : t->id, -1, x); + } + } + return; + case act_field: + if (T->data) { + tl_buf_add_string_q ((char *)T->data, -1, x); + x = 0; + tl_buf_add_string_q (":", -1, 0); + } + tl_buf_add_tree (T->left, x); + tl_buf_add_tree (T->right, 1); + return; + case act_union: + tl_buf_add_tree (T->left, x); + tl_buf_add_tree (T->right, 1); + return; + case act_var: + { + if (T->data == (void *)-1l) { return; } + struct tl_combinator_tree *v = T->data; + tl_buf_add_string_q ((char *)v->data, -1, x); + if (T->type == type_num && T->type_flags) { + static char _buf[30]; + sprintf (_buf, "+%lld", T->type_flags); + tl_buf_add_string_q (_buf, -1, 0); + } + } + return; + case act_arg: + tl_buf_add_tree (T->left, x); + tl_buf_add_tree (T->right, 1); + return; + case act_array: + if (T->left && !(T->left->flags & 128)) { + tl_buf_add_tree (T->left, x); + x = 0; + tl_buf_add_string_q ("*", -1, x); + } + tl_buf_add_string_q ("[", -1, x); + tl_buf_add_tree (T->right, 1); + tl_buf_add_string_q ("]", -1, 1); + return; + case act_plus: + tl_buf_add_tree (T->left, x); + tl_buf_add_string_q ("+", -1, 0); + tl_buf_add_tree (T->right, 0); + return; + case act_nat_const: + { + static char _buf[30]; + snprintf (_buf, 29, "%lld", T->type_flags); + tl_buf_add_string_q (_buf, -1, x); + return; + } + case act_opt_field: + { + struct tl_combinator_tree *v = T->left->data; + tl_buf_add_string_q ((char *)v->data, -1, x); + tl_buf_add_string_q (".", -1, 0); + static char _buf[30]; + sprintf (_buf, "%lld", T->left->type_flags); + tl_buf_add_string_q (_buf, -1, 0); + tl_buf_add_string_q ("?", -1, 0); + tl_buf_add_tree (T->right, 0); + return; + } + + default: + fprintf (stderr, "%s %s\n", TL_ACT (T->act), TL_TYPE (T->type)); + assert (0); + return; + } +} + +int tl_count_combinator_name (struct tl_constructor *c) { + assert (c); + tl_buf_reset (); + tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1); + tl_buf_add_tree (c->left, 1); + tl_buf_add_string ("=", -1); + tl_buf_add_tree (c->right, 1); + //fprintf (stderr, "%.*s\n", buf_pos, buf); + if (!c->name) { + c->name = compute_crc32 (buf, buf_pos); + } + return c->name; +} + +int tl_print_combinator (struct tl_constructor *c) { + tl_buf_reset (); + tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1); + static char _buf[10]; + sprintf (_buf, "#%08x", c->name); + tl_buf_add_string_nospace (_buf, -1); + tl_buf_add_tree (c->left, 1); + tl_buf_add_string ("=", -1); + tl_buf_add_tree (c->right, 1); + if (output_expressions >= 1) { + fprintf (stderr, "%.*s\n", buf_pos, buf); + } +/* if (!c->name) { + c->name = compute_crc32 (buf, buf_pos); + }*/ + return c->name; +} + +int _tl_finish_subtree (struct tl_combinator_tree *R, int x, long long y) { + assert (R->type == type_type); + assert (R->type_len < 0); + assert (R->act == act_arg || R->act == act_type); + R->type_len = x; + R->type_flags = y; + if (R->act == act_type) { + struct tl_type *t = R->data; + assert (t); + return tl_type_set_params (t, x, y); + } + assert ((R->right->type == type_type && R->right->type_len == 0) || R->right->type == type_num || R->right->type == type_num_value); + return _tl_finish_subtree (R->left, x + 1, y * 2 + (R->right->type == type_num || R->right->type == type_num_value)); +} + +int tl_finish_subtree (struct tl_combinator_tree *R) { + assert (R); + if (R->type != type_type) { + return 1; + } + if (R->type_len >= 0) { + if (R->type_len > 0) { + TL_ERROR ("Not enough params\n"); + return 0; + } + return 1; + } + return _tl_finish_subtree (R, 0, 0); +} + +struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_combinator_tree *R) { + if (!L) { return R; } + if (!R) { return L; } + TL_INIT (v); + v = alloc_ctree_node (); + v->left = L; + v->right = R; + switch (L->type) { + case type_num: + if (R->type != type_num_value) { + TL_ERROR ("Union: type mistmatch\n"); + return 0; + } + tfree (v, sizeof (*v)); + L->type_flags += R->type_flags; + return L; + case type_num_value: + if (R->type != type_num_value && R->type != type_num) { + TL_ERROR ("Union: type mistmatch\n"); + return 0; + } + tfree (v, sizeof (*v)); + R->type_flags += L->type_flags; + return R; + case type_list_item: + case type_list: + if (R->type != type_list_item) { + TL_ERROR ("Union: type mistmatch\n"); + return 0; + } + v->type = type_list; + v->act = act_union; + return v; + case type_type: + if (L->type_len == 0) { + TL_ERROR ("Arguments number exceeds type arity\n"); + return 0; + } + if (R->type != type_num && R->type != type_type && R->type != type_num_value) { + TL_ERROR ("Union: type mistmatch\n"); + return 0; + } + if (R->type_len < 0) { + if (!tl_finish_subtree (R)) { + return 0; + } + } + if (R->type_len > 0) { + TL_ERROR ("Argument type must have full number of arguments\n"); + return 0; + } + if (L->type_len > 0 && ((L->type_flags & 1) != (R->type == type_num || R->type == type_num_value))) { + TL_ERROR ("Argument types mistmatch: L->type_flags = %lld, R->type = %s\n", L->flags, TL_TYPE (R->type)); + return 0; + } + v->type = type_type; + v->act = act_arg; + v->type_len = L->type_len > 0 ? L->type_len - 1 : -1; + v->type_flags = L->type_flags >> 1; + return v; + default: + assert (0); + return 0; + } +} + +struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s); +struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) { + assert (T->type == type_term); + int i = 0; + while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; } + assert (i < T->nc); + TL_INIT (L); + while (i < T->nc) { + TL_TRY (tl_parse_any_term (T->c[i], s), L); + s = 0; + i ++; + } + return L; +} + + +struct tl_combinator_tree *tl_parse_type_term (struct tree *T, int s) { + assert (T->type == type_type_term); + assert (T->nc == 1); + struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s); + if (!Z || Z->type != type_type) { if (Z) { TL_ERROR ("type_term: found type %s\n", TL_TYPE (Z->type)); } TL_FAIL; } + return Z; +} + +struct tl_combinator_tree *tl_parse_nat_term (struct tree *T, int s) { + assert (T->type == type_nat_term); + assert (T->nc == 1); + struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s); + if (!Z || (Z->type != type_num && Z->type != type_num_value)) { if (Z) { TL_ERROR ("nat_term: found type %s\n", TL_TYPE (Z->type)); }TL_FAIL; } + return Z; +} + +struct tl_combinator_tree *tl_parse_subexpr (struct tree *T, int s) { + assert (T->type == type_subexpr); + assert (T->nc >= 1); + int i; + TL_INIT (L); + for (i = 0; i < T->nc; i++) { + TL_TRY (tl_parse_any_term (T->c[i], s), L); + s = 0; + } + return L; +} + +struct tl_combinator_tree *tl_parse_expr (struct tree *T, int s) { + assert (T->type == type_expr); + assert (T->nc >= 1); + int i; + TL_INIT (L); + for (i = 0; i < T->nc; i++) { + TL_TRY (tl_parse_subexpr (T->c[i], s), L); + s = 0; + } + return L; +} + +struct tl_combinator_tree *tl_parse_nat_const (struct tree *T, int s) { + assert (T->type == type_nat_const); + assert (!T->nc); + if (s > 0) { + TL_ERROR ("Nat const can not preceed with %%\n"); + TL_FAIL; + } + assert (T->type == type_nat_const); + assert (!T->nc); + TL_INIT (L); + L = alloc_ctree_node (); + L->act = act_nat_const; + L->type = type_num_value; + int i; + long long x = 0; + for (i = 0; i < T->len; i++) { + x = x * 10 + T->text[i] - '0'; + } + L->type_flags = x; + return L; +} + +struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) { + assert (T->type == type_type_ident || T->type == type_var_ident || T->type == type_boxed_type_ident); + assert (!T->nc); + struct tl_var *v = tl_get_var (T->text, T->len); + TL_INIT (L); + if (v) { + L = alloc_ctree_node (); + L->act = act_var; + L->type = v->type ? type_num : type_type; + if (L->type == type_num && s) { + TL_ERROR ("Nat var can not preceed with %%\n"); + TL_FAIL; + } else { + if (s) { + L->flags |= 1; + } + } + L->type_len = 0; + L->type_flags = 0; + L->data = v->ptr; + return L; + } + +/* if (!mystrcmp2 (T->text, T->len, "#") || !mystrcmp2 (T->text, T->len, "Type")) { + L = alloc_ctree_node (); + L->act = act_type; + L->flags |= 2; + L->data = tl_get_type (T->text, T->len); + assert (L->data); + L->type = type_type; + L->type_len = 0; + L->type_flags = 0; + return L; + }*/ + + struct tl_constructor *c = tl_get_constructor (T->text, T->len); + if (c) { + assert (c->type); + if (c->type->constructors_num != 1) { + TL_ERROR ("Constructor can be used only if it is the only constructor of the type\n"); + return 0; + } + c->type->flags |= 1; + L = alloc_ctree_node (); + L->act = act_type; + L->flags |= 5; + L->data = c->type; + L->type = type_type; + L->type_len = c->type->params_num; + L->type_flags = c->type->params_types; + return L; + } + int x = tl_is_type_name (T->text, T->len); + if (x) { + struct tl_type *t = tl_add_type (T->text, T->len, -1, 0); + L = alloc_ctree_node (); + if (s) { + L->flags |= 1; + t->flags |= 8; + } + L->act = act_type; + L->data = t; + L->type = type_type; + L->type_len = t->params_num; + L->type_flags = t->params_types; + return L; + } else { + TL_ERROR ("Not a type/var ident `%.*s`\n", T->len, T->text); + return 0; + } +} + +struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s) { + switch (T->type) { + case type_type_term: + return tl_parse_type_term (T, s); + case type_nat_term: + return tl_parse_nat_term (T, s); + case type_term: + return tl_parse_term (T, s); + case type_expr: + return tl_parse_expr (T, s); + case type_subexpr: + return tl_parse_subexpr (T, s); + case type_nat_const: + return tl_parse_nat_const (T, s); + case type_type_ident: + case type_var_ident: + return tl_parse_ident (T, s); + default: + fprintf (stderr, "type = %d\n", T->type); + assert (0); + return 0; + } +} + +struct tl_combinator_tree *tl_parse_multiplicity (struct tree *T) { + assert (T->type == type_multiplicity); + assert (T->nc == 1); + return tl_parse_nat_term (T->c[0], 0); +} + +struct tl_combinator_tree *tl_parse_opt_args (struct tree *T) { + assert (T); + assert (T->type == type_opt_args); + assert (T->nc >= 2); + TL_INIT (R); + TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R); + assert (R->type == type_type && !R->type_len); + assert (tl_finish_subtree (R)); + struct tl_type *t = tl_tree_get_type (R); + //assert (t); + int tt = -1; + if (t && !strcmp (t->id, "#")) { + tt = 1; + } else if (t && !strcmp (t->id, "Type")) { + tt = 0; + } + if (tt < 0) { + TL_ERROR ("Optargs can be only of type # or Type\n"); + TL_FAIL; + } + + int i; + for (i = 0; i < T->nc - 1; i++) { + if (T->c[i]->type != type_var_ident) { + TL_ERROR ("Variable name expected\n"); + TL_FAIL; + } + if (T->c[i]->len == 1 && *T->c[i]->text == '_') { + TL_ERROR ("Variables can not be unnamed\n"); + TL_FAIL; + } + } + TL_INIT (H); +// for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) { + for (i = 0; i <= T->nc - 2; i++) { + TL_INIT (S); S = alloc_ctree_node (); + S->left = (i == T->nc - 2) ? R : tl_tree_dup (R) ; S->right = 0; + S->type = type_list_item; + S->type_len = 0; + S->act = act_field; + S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0; + if (tt >= 0) { + assert (S->data); + tl_add_var (S->data, S, tt); + } + S->flags = 33; + H = tl_union (H, S); + } + return H; +} + +struct tl_combinator_tree *tl_parse_args (struct tree *T); +struct tl_combinator_tree *tl_parse_args2 (struct tree *T) { + assert (T); + assert (T->type == type_args2); + assert (T->nc >= 1); + TL_INIT (R); + TL_INIT (L); + int x = 0; + char *field_name = 0; + if (T->c[x]->type == type_var_ident_opt || T->c[x]->type == type_var_ident) { + field_name = mystrdup (T->c[x]->text, T->c[x]->len); + if (!tl_add_field (field_name)) { + TL_ERROR ("Duplicate field name %s\n", field_name); + TL_FAIL; + } + x ++; + } + //fprintf (stderr, "%d %d\n", x, T->nc); + if (T->c[x]->type == type_multiplicity) { + L = tl_parse_multiplicity (T->c[x]); + if (!L) { TL_FAIL;} + x ++; + } else { + struct tl_var *v = tl_get_last_num_var (); + if (!v) { + TL_ERROR ("Expected multiplicity or nat var\n"); + TL_FAIL; + } + L = alloc_ctree_node (); + L->act = act_var; + L->type = type_num; + L->flags |= 128; + L->type_len = 0; + L->type_flags = 0; + L->data = v->ptr; + ((struct tl_combinator_tree *)(v->ptr))->flags |= 256; + } + namespace_push (); + while (x < T->nc) { + TL_TRY (tl_parse_args (T->c[x]), R); + x ++; + } + namespace_pop (); + struct tl_combinator_tree *S = alloc_ctree_node (); + S->type = type_type; + S->type_len = 0; + S->act = act_array; + S->left = L; + S->right = R; + //S->data = field_name; + + struct tl_combinator_tree *H = alloc_ctree_node (); + H->type = type_list_item; + H->act = act_field; + H->left = S; + H->right = 0; + H->data = field_name; + H->type_len = 0; + + return H; +} + +void tl_mark_vars (struct tl_combinator_tree *T); +struct tl_combinator_tree *tl_parse_args134 (struct tree *T) { + assert (T); + assert (T->type == type_args1 || T->type == type_args3 || T->type == type_args4); + assert (T->nc >= 1); + TL_INIT (R); + TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R); + assert (tl_finish_subtree (R)); + assert (R->type == type_type && !R->type_len); + struct tl_type *t = tl_tree_get_type (R); + //assert (t); + int tt = -1; + if (t && !strcmp (t->id, "#")) { + tt = 1; + } else if (t && !strcmp (t->id, "Type")) { + tt = 0; + } + +/* if (tt >= 0 && T->nc == 1) { + TL_ERROR ("Variables can not be unnamed (type %d)\n", tt); + }*/ + int last = T->nc - 2; + int excl = 0; + if (last >= 0 && T->c[last]->type == type_exclam) { + excl ++; + tl_mark_vars (R); + last --; + } + if (last >= 0 && T->c[last]->type == type_optional_arg_def) { + assert (T->c[last]->nc == 2); + TL_INIT (E); E = alloc_ctree_node (); + E->type = type_type; + E->act = act_opt_field; + E->left = tl_parse_ident (T->c[last]->c[0], 0); + int i; + long long x = 0; + for (i = 0; i < T->c[last]->c[1]->len; i++) { + x = x * 10 + T->c[last]->c[1]->text[i] - '0'; + } + E->left->type_flags = x; + E->type_flags = R->type_flags; + E->type_len = R->type_len; + E->right = R; + R = E; + last --; + } + int i; + for (i = 0; i < last; i++) { + if (T->c[i]->type != type_var_ident && T->c[i]->type != type_var_ident_opt) { + TL_ERROR ("Variable name expected\n"); + TL_FAIL; + } +/* if (tt >= 0 && (T->nc == 1 || (T->c[i]->len == 1 && *T->c[i]->text == '_'))) { + TL_ERROR ("Variables can not be unnamed\n"); + TL_FAIL; + }*/ + } + TL_INIT (H); +// for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) { + for (i = (last >= 0 ? 0 : -1); i <= last; i++) { + TL_INIT (S); S = alloc_ctree_node (); + S->left = (i == last) ? R : tl_tree_dup (R) ; S->right = 0; + S->type = type_list_item; + S->type_len = 0; + S->act = act_field; + S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0; + if (excl) { + S->flags |= FLAG_EXCL; + } + if (S->data && (T->c[i]->len >= 2 || *T->c[i]->text != '_')) { + if (!tl_add_field (S->data)) { + TL_ERROR ("Duplicate field name %s\n", (char *)S->data); + TL_FAIL; + } + } + if (tt >= 0) { + //assert (S->data); + char *name = S->data; + if (!name) { + static char s[20]; + sprintf (s, "%lld", lrand48 () * (1ll << 32) + lrand48 ()); + name = s; + } + struct tl_var *v = tl_add_var (name, S, tt); + if (!v) {TL_FAIL;} + v->flags |= 2; + } + + H = tl_union (H, S); + } + return H; +} + + +struct tl_combinator_tree *tl_parse_args (struct tree *T) { + assert (T->type == type_args); + assert (T->nc == 1); + switch (T->c[0]->type) { + case type_args1: + return tl_parse_args134 (T->c[0]); + case type_args2: + return tl_parse_args2 (T->c[0]); + case type_args3: + return tl_parse_args134 (T->c[0]); + case type_args4: + return tl_parse_args134 (T->c[0]); + default: + assert (0); + return 0; + } +} + +void tl_mark_vars (struct tl_combinator_tree *T) { + if (!T) { return; } + if (T->act == act_var) { + char *id = ((struct tl_combinator_tree *)(T->data))->data; + struct tl_var *v = tl_get_var (id, strlen (id)); + assert (v); + v->flags |= 1; + } + tl_mark_vars (T->left); + tl_mark_vars (T->right); +} + +struct tl_combinator_tree *tl_parse_result_type (struct tree *T) { + assert (T->type == type_result_type); + assert (T->nc >= 1); + assert (T->nc <= 64); + + TL_INIT (L); + + if (tl_get_var (T->c[0]->text, T->c[0]->len)) { + if (T->nc != 1) { + TL_ERROR ("Variable can not take params\n"); + TL_FAIL; + } + L = alloc_ctree_node (); + L->act = act_var; + L->type = type_type; + struct tl_var *v = tl_get_var (T->c[0]->text, T->c[0]->len); + if (v->type) { + TL_ERROR ("Type mistmatch\n"); + TL_FAIL; + } + L->data = v->ptr; +// assert (v->ptr); + } else { + L = alloc_ctree_node (); + L->act = act_type; + L->type = type_type; + struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, -1, 0); + assert (t); + L->type_len = t->params_num; + L->type_flags = t->params_types; + L->data = t; + + int i; + for (i = 1; i < T->nc; i++) { + TL_TRY (tl_parse_any_term (T->c[i], 0), L); + assert (L->right); + assert (L->right->type == type_num || L->right->type == type_num_value || (L->right->type == type_type && L->right->type_len == 0)); + } + } + + if (!tl_finish_subtree (L)) { + TL_FAIL; + } + + tl_mark_vars (L); + return L; +} + +int __ok; +void tl_var_check_used (struct tl_var *v) { + __ok = __ok && (v->flags & 3); +} + +int tl_parse_combinator_decl (struct tree *T, int fun) { + assert (T->type == type_combinator_decl); + assert (T->nc >= 3); + namespace_level = 0; + tl_clear_vars (); + tl_clear_fields (); + TL_INIT (L); + TL_INIT (R); + + int i = 1; + while (i < T->nc - 2 && T->c[i]->type == type_opt_args) { + TL_TRY (tl_parse_opt_args (T->c[i]), L); + i++; + } + while (i < T->nc - 2 && T->c[i]->type == type_args) { + TL_TRY (tl_parse_args (T->c[i]), L); + i++; + } + assert (i == T->nc - 2 && T->c[i]->type == type_equals); + i ++; + + R = tl_parse_result_type (T->c[i]); + if (!R) { TL_FAIL; } + + struct tl_type *t = tl_tree_get_type (R); + if (!fun && !t) { + TL_ERROR ("Only functions can return variables\n"); + } + assert (t || fun); + + assert (namespace_level == 0); + __ok = 1; + tree_act_tl_var (vars[0], tl_var_check_used); + if (!__ok) { + TL_ERROR ("Not all variables are used in right side\n"); + TL_FAIL; + } + + if (tl_get_constructor (T->c[0]->text, T->c[0]->len) || tl_get_function (T->c[0]->text, T->c[0]->len)) { + TL_ERROR ("Duplicate combinator id %.*s\n", T->c[0]->len, T->c[0]->text); + return 0; + } + struct tl_constructor *c = !fun ? tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0) : tl_add_function (t, T->c[0]->text, T->c[0]->len, 0); + if (!c) { TL_FAIL; } + c->left = L; + c->right = R; + + if (!c->name) { + tl_count_combinator_name (c); + } + tl_print_combinator (c); + + return 1; +} + +void change_var_ptrs (struct tl_combinator_tree *O, struct tl_combinator_tree *D, struct tree_var_value **V) { + if (!O || !D) { + assert (!O && !D); + return; + } + if (O->act == act_field) { + struct tl_type *t = tl_tree_get_type (O->left); + if (t && (!strcmp (t->id, "#") || !strcmp (t->id, "Type"))) { + tl_set_var_value (V, O, D); + } + } + if (O->act == act_var) { + assert (D->data == O->data); + D->data = tl_get_var_value (V, O->data); + assert (D->data); + } + change_var_ptrs (O->left, D->left, V); + change_var_ptrs (O->right, D->right, V); +} + +struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struct tl_combinator_tree **X, struct tl_combinator_tree *Y) { + if (!O) { return (void *)-2l; }; + if (O->act == act_field && !*X) { + struct tl_type *t = tl_tree_get_type (O->left); + if (t && !strcmp (t->id, "#")) { + if (Y->type != type_num && Y->type != type_num_value) { + TL_ERROR ("change_var: Type mistmatch\n"); + return 0; + } else { + *X = O; + return (void *)-1l; + } + } + if (t && !strcmp (t->id, "Type")) { + if (Y->type != type_type || Y->type_len != 0) { + TL_ERROR ("change_var: Type mistmatch\n"); + return 0; + } else { + *X = O; + return (void *)-1l; + } + } + } + if (O->act == act_var) { + if (O->data == *X) { + struct tl_combinator_tree *R = tl_tree_dup (Y); + if (O->type == type_num || O->type == type_num_value) { R->type_flags += O->type_flags; } + return R; + } + } + struct tl_combinator_tree *t; + t = change_first_var (O->left, X, Y); + if (!t) { return 0;} + if (t == (void *)-1l) { + t = change_first_var (O->right, X, Y); + if (!t) { return 0;} + if (t == (void *)-1l) { return (void *)-1l; } + if (t != (void *)-2l) { return t;} + return (void *)-1l; + } + if (t != (void *)-2l) { + O->left = t; + } + t = change_first_var (O->right, X, Y); + if (!t) { return 0;} + if (t == (void *)-1l) { + return O->left; + } + if (t != (void *)-2l) { + O->right = t; + } + return O; +} + + +int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T); +struct tree_var_value **_T; +int __tok; +void check_nat_val (struct tl_var_value v) { + if (!__tok) { return; } + long long x = v.num_val; + struct tl_combinator_tree *L = v.val; + if (L->type == type_type) { return;} + while (1) { + if (L->type == type_num_value) { + if (x + L->type_flags < 0) { + __tok = 0; + return; + } else { + return; + } + } + assert (L->type == type_num); + x += L->type_flags; + x += tl_get_var_value_num (_T, L->data); + L = tl_get_var_value (_T, L->data); + if (!L) { return;} + } +} + +int check_constructors_equal (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) { + if (!uniformize (L, R, T)) { return 0; } + __tok = 1; + _T = T; + tree_act_var_value (*T, check_nat_val); + return __tok; +} + +struct tl_combinator_tree *reduce_type (struct tl_combinator_tree *A, struct tl_type *t) { + assert (A); + if (A->type_len == t->params_num) { + assert (A->type_flags == t->params_types); + A->act = act_type; + A->type = type_type; + A->left = A->right = 0; + A->data = t; + return A; + } + A->left = reduce_type (A->left, t); + return A; +} + +struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struct tree_var_value **X) { + if (!O) { return (void *)-2l; }; + while (O->act == act_var) { + assert (O->data); + if (!tl_get_var_value (X, O->data)) { + break; + } + if (O->type == type_type) { + O = tl_tree_dup (tl_get_var_value (X, O->data)); + } else { + long long n = tl_get_var_value_num (X, O->data); + struct tl_combinator_tree *T = tl_get_var_value (X, O->data); + O->data = T->data; + O->type = T->type; + O->act = T->act; + O->type_flags = O->type_flags + n + T->type_flags; + } + } + if (O->act == act_field) { + if (tl_get_var_value (X, O)) { return (void *)-1l; } + } + struct tl_combinator_tree *t; + t = change_value_var (O->left, X); + if (!t) { return 0;} + if (t == (void *)-1l) { + t = change_value_var (O->right, X); + if (!t) { return 0;} + if (t == (void *)-1l) { return (void *)-1l; } + if (t != (void *)-2l) { return t;} + return (void *)-1l; + } + if (t != (void *)-2l) { + O->left = t; + } + t = change_value_var (O->right, X); + if (!t) { return 0;} + if (t == (void *)-1l) { + return O->left; + } + if (t != (void *)-2l) { + O->right = t; + } + return O; +} + +int tl_parse_partial_type_app_decl (struct tree *T) { + assert (T->type == type_partial_type_app_decl); + assert (T->nc >= 1); + + assert (T->c[0]->type == type_boxed_type_ident); + struct tl_type *t = tl_get_type (T->c[0]->text, T->c[0]->len); + if (!t) { + TL_ERROR ("Can not make partial app for unknown type\n"); + return 0; + } + + tl_type_finalize (t); + + struct tl_combinator_tree *L = tl_parse_ident (T->c[0], 0); + assert (L); + int i; + tl_buf_reset (); + int cc = T->nc - 1; + for (i = 1; i < T->nc; i++) { + TL_TRY (tl_parse_any_term (T->c[i], 0), L); + tl_buf_add_tree (L->right, 1); + } + + while (L->type_len) { + struct tl_combinator_tree *C = alloc_ctree_node (); + C->act = act_var; + C->type = (L->type_flags & 1) ? type_num : type_type; + C->type_len = 0; + C->type_flags = 0; + C->data = (void *)-1l; + L = tl_union (L, C); + if (!L) { return 0; } + } + + + static char _buf[100000]; + snprintf (_buf, 100000, "%s%.*s", t->id, buf_pos, buf); + struct tl_type *nt = tl_add_type (_buf, strlen (_buf), t->params_num - cc, t->params_types >> cc); + assert (nt); + //snprintf (_buf, 100000, "%s #", t->id); + //nt->real_id = strdup (_buf); + + for (i = 0; i < t->constructors_num; i++) { + struct tl_constructor *c = t->constructors[i]; + struct tree_var_value *V = 0; + TL_INIT (A); + TL_INIT (B); + A = tl_tree_dup (c->left); + B = tl_tree_dup (c->right); + + struct tree_var_value *W = 0; + change_var_ptrs (c->left, A, &W); + change_var_ptrs (c->right, B, &W); + + + if (!check_constructors_equal (B, L, &V)) { continue; } + B = reduce_type (B, nt); + A = change_value_var (A, &V); + if (A == (void *)-1l) { A = 0;} + B = change_value_var (B, &V); + assert (B != (void *)-1l); + snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf); + + struct tl_constructor *r = tl_add_constructor (nt, _buf, strlen (_buf), 1); + snprintf (_buf, 100000, "%s", c->id); + r->real_id = tstrdup (_buf); + + r->left = A; + r->right = B; + if (!r->name) { + tl_count_combinator_name (r); + } + tl_print_combinator (r); + } + + return 1; +} + +int tl_parse_partial_comb_app_decl (struct tree *T, int fun) { + assert (T->type == type_partial_comb_app_decl); + + struct tl_constructor *c = !fun ? tl_get_constructor (T->c[0]->text, T->c[0]->len) : tl_get_function (T->c[0]->text, T->c[0]->len); + if (!c) { + TL_ERROR ("Can not make partial app for undefined combinator\n"); + return 0; + } + + //TL_INIT (K); + //static char buf[1000]; + //int x = sprintf (buf, "%s", c->id); + TL_INIT (L); + TL_INIT (R); + L = tl_tree_dup (c->left); + R = tl_tree_dup (c->right); + + + struct tree_var_value *V = 0; + change_var_ptrs (c->left, L, &V); + change_var_ptrs (c->right, R, &V); + V = tree_clear_var_value (V); + + int i; + tl_buf_reset (); + for (i = 1; i < T->nc; i++) { + TL_INIT (X); + TL_INIT (Z); + X = tl_parse_any_term (T->c[i], 0); + struct tl_combinator_tree *K = 0; + if (!(Z = change_first_var (L, &K, X))) { + TL_FAIL; + } + L = Z; + if (!K) { + TL_ERROR ("Partial app: not enougth variables (i = %d)\n", i); + TL_FAIL; + } + if (!(Z = change_first_var (R, &K, X))) { + TL_FAIL; + } + assert (Z == R); + tl_buf_add_tree (X, 1); + } + + static char _buf[100000]; + snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf); +// fprintf (stderr, "Local id: %s\n", _buf); + + struct tl_constructor *r = !fun ? tl_add_constructor (c->type, _buf, strlen (_buf), 1) : tl_add_function (c->type, _buf, strlen (_buf), 1); + r->left = L; + r->right = R; + snprintf (_buf, 100000, "%s", c->id); + r->real_id = tstrdup (_buf); + if (!r->name) { + tl_count_combinator_name (r); + } + tl_print_combinator (r); + return 1; +} + + +int tl_parse_partial_app_decl (struct tree *T, int fun) { + assert (T->type == type_partial_app_decl); + assert (T->nc == 1); + if (T->c[0]->type == type_partial_comb_app_decl) { + return tl_parse_partial_comb_app_decl (T->c[0], fun); + } else { + if (fun) { + TL_ERROR ("Partial type app in functions block\n"); + TL_FAIL; + } + return tl_parse_partial_type_app_decl (T->c[0]); + } +} + +int tl_parse_final_final (struct tree *T) { + assert (T->type == type_final_final); + assert (T->nc == 1); + struct tl_type *R; + if ((R = tl_get_type (T->c[0]->text, T->c[0]->len))) { + R->flags |= 1; + return 1; + } else { + TL_ERROR ("Final statement for type `%.*s` before declaration\n", T->c[0]->len, T->c[0]->text); + TL_FAIL; + } +} + +int tl_parse_final_new (struct tree *T) { + assert (T->type == type_final_new); + assert (T->nc == 1); + if (tl_get_type (T->c[0]->text, T->c[0]->len)) { + TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text); + TL_FAIL; + } else { + return 1; + } +} + +int tl_parse_final_empty (struct tree *T) { + assert (T->type == type_final_empty); + assert (T->nc == 1); + if (tl_get_type (T->c[0]->text, T->c[0]->len)) { + TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text); + TL_FAIL; + } + struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, 0, 0); + assert (t); + t->flags |= 1 | FLAG_EMPTY; + return 1; +} + +int tl_parse_final_decl (struct tree *T, int fun) { + assert (T->type == type_final_decl); + assert (!fun); + assert (T->nc == 1); + switch (T->c[0]->type) { + case type_final_new: + return tl_parse_final_new (T->c[0]); + case type_final_final: + return tl_parse_final_final (T->c[0]); + case type_final_empty: + return tl_parse_final_empty (T->c[0]); + default: + assert (0); + return 0; + } +} + +int tl_parse_builtin_combinator_decl (struct tree *T, int fun) { + if (fun) { + TL_ERROR ("Builtin type can not be described in function block\n"); + return -1; + } + assert (T->type == type_builtin_combinator_decl); + assert (T->nc == 2); + assert (T->c[0]->type == type_full_combinator_id); + assert (T->c[1]->type == type_boxed_type_ident); + + + if ((!mystrcmp2 (T->c[0]->text, T->c[0]->len, "int") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Int")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "long") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Long")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "double") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Double")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "object") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Object")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "function") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Function")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "string") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "String"))) { + struct tl_type *t = tl_add_type (T->c[1]->text, T->c[1]->len, 0, 0); + if (!t) { + return 0; + } + struct tl_constructor *c = tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0); + if (!c) { + return 0; + } + + c->left = alloc_ctree_node (); + c->left->act = act_question_mark; + c->left->type = type_list_item; + + c->right = alloc_ctree_node (); + c->right->act = act_type; + c->right->data = t; + c->right->type = type_type; + + if (!c->name) { + tl_count_combinator_name (c); + } + tl_print_combinator (c); + } else { + TL_ERROR ("Unknown builting type `%.*s`\n", T->c[0]->len, T->c[0]->text); + return 0; + } + + return 1; +} + +int tl_parse_declaration (struct tree *T, int fun) { + assert (T->type == type_declaration); + assert (T->nc == 1); + switch (T->c[0]->type) { + case type_combinator_decl: + return tl_parse_combinator_decl (T->c[0], fun); + case type_partial_app_decl: + return tl_parse_partial_app_decl (T->c[0], fun); + case type_final_decl: + return tl_parse_final_decl (T->c[0], fun); + case type_builtin_combinator_decl: + return tl_parse_builtin_combinator_decl (T->c[0], fun); + default: + assert (0); + return 0; + } +} + +int tl_parse_constr_declarations (struct tree *T) { + assert (T->type == type_constr_declarations); + int i; + for (i = 0; i < T->nc; i++) { + TL_TRY_PES (tl_parse_declaration (T->c[i], 0)); + } + return 1; +} + +int tl_parse_fun_declarations (struct tree *T) { + assert (T->type == type_fun_declarations); + int i; + for (i = 0; i < T->nc; i++) { + TL_TRY_PES (tl_parse_declaration (T->c[i], 1)); + } + return 1; +} + +int tl_tree_lookup_value (struct tl_combinator_tree *L, void *var, struct tree_var_value **T) { + if (!L) { + return -1; + } + if (L->act == act_var && L->data == var) { + return 0; + } + if (L->act == act_var) { + struct tl_combinator_tree *E = tl_get_var_value (T, L->data); + if (!E) { return -1;} + else { return tl_tree_lookup_value (E, var, T); } + } + if (tl_tree_lookup_value (L->left, var, T) >= 0) { return 1; } + if (tl_tree_lookup_value (L->right, var, T) >= 0) { return 1; } + return -1; +} + +int tl_tree_lookup_value_nat (struct tl_combinator_tree *L, void *var, long long x, struct tree_var_value **T) { + assert (L); + if (L->type == type_num_value) { return -1; } + assert (L->type == type_num); + assert (L->act == act_var); + if (L->data == var) { + return x == L->type_flags ? 0 : 1; + } else { + if (!tl_get_var_value (T, L->data)) { + return -1; + } + return tl_tree_lookup_value_nat (tl_get_var_value (T, L->data), var, x + tl_get_var_value_num (T, L->data), T); + } + +} + +int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) { + if (!L || !R) { + assert (!L && !R); + return 1; + } + if (R->act == act_var) { + struct tl_combinator_tree *_ = R; R = L; L = _; + } + + if (L->type == type_type) { + if (R->type != type_type || L->type_len != R->type_len || L->type_flags != R->type_flags) { + return 0; + } + if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;} + if (L->act == act_var) { + int x = tl_tree_lookup_value (R, L->data, T); + if (x > 0) { +// if (tl_tree_lookup_value (R, L->data, T) > 0) { + return 0; + } + if (x == 0) { + return 1; + } + struct tl_combinator_tree *E = tl_get_var_value (T, L->data); + if (!E) { + tl_set_var_value (T, L->data, R); + return 1; + } else { + return uniformize (E, R, T); + } + } else { + if (L->act != R->act || L->data != R->data) { + return 0; + } + return uniformize (L->left, R->left, T) && uniformize (L->right, R->right, T); + } + } else { + assert (L->type == type_num || L->type == type_num_value); + if (R->type != type_num && R->type != type_num_value) { + return 0; + } + assert (R->type == type_num || R->type == type_num_value); + if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;} + long long x = 0; + struct tl_combinator_tree *K = L; + while (1) { + x += K->type_flags; + if (K->type == type_num_value) { + break; + } + if (!tl_get_var_value (T, K->data)) { + int s = tl_tree_lookup_value_nat (R, K->data, K->type_flags, T); + if (s > 0) { + return 0; + } + if (s == 0) { + return 1; + } + /*tl_set_var_value_num (T, K->data, R, -x); + return 1;*/ + break; + } + x += tl_get_var_value_num (T, K->data); + K = tl_get_var_value (T, K->data); + } + long long y = 0; + struct tl_combinator_tree *M = R; + while (1) { + y += M->type_flags; + if (M->type == type_num_value) { + break; + } + if (!tl_get_var_value (T, M->data)) { + int s = tl_tree_lookup_value_nat (L, M->data, M->type_flags, T); + if (s > 0) { + return 0; + } + if (s == 0) { + return 1; + } + /*tl_set_var_value_num (T, M->data, L, -y); + return 1;*/ + break; + } + y += tl_get_var_value_num (T, M->data); + M = tl_get_var_value (T, M->data); + } + if (K->type == type_num_value && M->type == type_num_value) { + return x == y; + } + if (M->type == type_num_value) { + tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags)); + return 1; + } else if (K->type == type_num_value) { + tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags)); + return 1; + } else { + if (x >= y) { + tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags)); + } else { + tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags)); + } + return 1; + } + } + return 0; +} + + +void tl_type_check (struct tl_type *t) { + if (!__ok) return; + if (!strcmp (t->id, "#")) { t->name = 0x70659eff; return; } + if (!strcmp (t->id, "Type")) { t->name = 0x2cecf817; return; } + if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) { + TL_ERROR ("Type %s has no constructors\n", t->id); + __ok = 0; + return; + } + int i, j; + t->name = 0; + for (i = 0; i < t->constructors_num; i++) { + t->name ^= t->constructors[i]->name; + } + for (i = 0; i < t->constructors_num; i++) { + for (j = i + 1; j < t->constructors_num; j++) { + struct tree_var_value *v = 0; + if (check_constructors_equal (t->constructors[i]->right, t->constructors[j]->right, &v)) { + t->flags |= 16; + } + } + } + if ((t->flags & 24) == 24) { + TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id); + } + int z = 0; + int sid = 0; + for (i = 0; i < t->constructors_num; i++) if (*t->constructors[i]->id == '_') { + z ++; + sid = i; + } + if (z > 1) { + TL_ERROR ("Type %s has %d default constructors\n", t->id, z); + __ok = 0; + return; + } + if (z == 1 && (t->flags & 8)) { + TL_ERROR ("Type %s has default constructors and used bare\n", t->id); + __ok = 0; + return; + } + if (z) { + struct tl_constructor *c; + c = t->constructors[sid]; + t->constructors[sid] = t->constructors[t->constructors_num - 1]; + t->constructors[t->constructors_num - 1] = c; + } +} + +struct tl_program *tl_parse (struct tree *T) { + assert (T); + assert (T->type == type_tl_program); + int i; + tl_program_cur = talloc (sizeof (*tl_program_cur)); + tl_add_type ("#", 1, 0, 0); + tl_add_type ("Type", 4, 0, 0); + for (i = 0; i < T->nc; i++) { + if (T->c[i]->type == type_constr_declarations) { TL_TRY_PES (tl_parse_constr_declarations (T->c[i])); } + else { TL_TRY_PES (tl_parse_fun_declarations (T->c[i])) } + } + __ok = 1; + tree_act_tl_type (tl_type_tree, tl_type_check); + if (!__ok) { + return 0; + } + return tl_program_cur; +} + +FILE *__f; +int num = 0; + +void wint (int a) { +// printf ("%d ", a); + a = htole32 (a); + assert (fwrite (&a, 1, 4, __f) == 4); +} + +void wdata (const void *x, int len) { + assert (fwrite (x, 1, len, __f) == len); +} + +void wstr (const char *s) { + if (s) { +// printf ("\"%s\" ", s); + int x = strlen (s); + if (x <= 254) { + unsigned char x_c = (unsigned char)x; + assert (fwrite (&x_c, 1, 1, __f) == 1); + } else { + fprintf (stderr, "String is too big...\n"); + assert (0); + } + wdata (s, x); + x ++; // The header, containing the length, which is 1 byte + int t = 0; + if (x & 3) { + // Let's hope it's truly zero on every platform + wdata (&t, 4 - (x & 3)); + } + } else { +// printf (" "); + wint (0); + } +} + +void wll (long long a) { +// printf ("%lld ", a); + a = htole64 (a); + assert (fwrite (&a, 1, 8, __f) == 8); +} + +int count_list_size (struct tl_combinator_tree *T) { + assert (T->type == type_list || T->type == type_list_item); + if (T->type == type_list_item) { + return 1; + } else { + return count_list_size (T->left) + count_list_size (T->right); + } +} + +void write_type_flags (long long flags) { + int new_flags = 0; + if (flags & 1) { + new_flags |= FLAG_BARE; + } + if (flags & FLAG_DEFAULT_CONSTRUCTOR) { + new_flags |= FLAG_DEFAULT_CONSTRUCTOR; + } + wint (new_flags); +} + +void write_field_flags (long long flags) { + int new_flags = 0; + //fprintf (stderr, "%lld\n", flags); + if (flags & 1) { + new_flags |= FLAG_BARE; + } + if (flags & 32) { + new_flags |= FLAG_OPT_VAR; + } + if (flags & FLAG_EXCL) { + new_flags |= FLAG_EXCL; + } + if (flags & FLAG_OPT_FIELD) { + // new_flags |= FLAG_OPT_FIELD; + new_flags |= 2; + } + if (flags & (1 << 21)) { + new_flags |= 4; + } + wint (new_flags); +} + +void write_var_type_flags (long long flags) { + int new_flags = 0; + if (flags & 1) { + new_flags |= FLAG_BARE; + } + if (new_flags & FLAG_BARE) { + TL_ERROR ("Sorry, bare vars are not (yet ?) supported.\n"); + assert (!(new_flags & FLAG_BARE)); + } + wint (new_flags); +} + +void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var); +void write_args (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { + assert (T->type == type_list || T->type == type_list_item); + if (T->type == type_list) { + assert (T->act == act_union); + assert (T->left); + assert (T->right); + write_args (T->left, v, last_var); + write_args (T->right, v, last_var); + return; + } + wint (TLS_ARG_V2); + assert (T->act == act_field); + assert (T->left); + wstr (T->data && strcmp (T->data, "_") ? T->data : 0); + long long f = T->flags; + if (T->left->act == act_opt_field) { + f |= (1 << 20); + } + if (T->left->act == act_type && T->left->data && (!strcmp (((struct tl_type *)T->left->data)->id, "#") || !strcmp (((struct tl_type *)T->left->data)->id, "Type"))) { + write_field_flags (f | (1 << 21)); + wint (*last_var); + *last_var = (*last_var) + 1; + tl_set_var_value_num (v, T, 0, (*last_var) - 1); + } else { + write_field_flags (f); + } + write_tree (T->left, 0, v, last_var); +} + +void write_array (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { + wint (TLS_ARRAY); + write_tree (T->left, 0, v, last_var); + write_tree (T->right, 0, v, last_var); +} + +void write_type_rec (struct tl_combinator_tree *T, int cc, struct tree_var_value **v, int *last_var) { + if (T->act == act_arg) { + write_type_rec (T->left, cc + 1, v, last_var); + if (T->right->type == type_num_value || T->right->type == type_num) { + wint (TLS_EXPR_NAT); + } else { + wint (TLS_EXPR_TYPE); + } + write_tree (T->right, 0, v, last_var); + } else { + assert (T->act == act_var || T->act == act_type); + if (T->act == act_var) { + assert (!cc); + wint (TLS_TYPE_VAR); + wint (tl_get_var_value_num (v, T->data)); + write_var_type_flags (T->flags); + //wint (T->flags); + } else { + wint (TLS_TYPE_EXPR); + struct tl_type *t = T->data; + wint (t->name); + write_type_flags (T->flags); +// wint (T->flags); + wint (cc); +// fprintf (stderr, "cc = %d\n", cc); + } + } +} + +void write_opt_type (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { + wint (tl_get_var_value_num (v, T->left->data)); + wint (T->left->type_flags); +// write_tree (T->right, 0, v, last_var); + assert (T); + T = T->right; + switch (T->type) { + case type_type: + if (T->act == act_array) { + write_array (T, v, last_var); + } else if (T->act == act_type || T->act == act_var || T->act == act_arg) { + write_type_rec (T, 0, v, last_var); + } else { + assert (0); + } + break; + default: + assert (0); + } +} + +void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var) { + assert (T); + switch (T->type) { + case type_list_item: + case type_list: + if (extra) { + wint (TLS_COMBINATOR_RIGHT_V2); + } + wint (count_list_size (T)); + write_args (T, v, last_var); + break; + case type_num_value: + wint ((int)TLS_NAT_CONST); + wint (T->type_flags); + break; + case type_num: + wint ((int)TLS_NAT_VAR); + wint (T->type_flags); + wint (tl_get_var_value_num (v, T->data)); + break; + case type_type: + if (T->act == act_array) { + write_array (T, v, last_var); + } else if (T->act == act_type || T->act == act_var || T->act == act_arg) { + write_type_rec (T, 0, v, last_var); + } else { + assert (T->act == act_opt_field); + write_opt_type (T, v, last_var); + } + break; + default: + assert (0); + } +} + +void write_type (struct tl_type *t) { + wint (TLS_TYPE); + wint (t->name); + wstr (t->id); + wint (t->constructors_num); + wint (t->flags); + wint (t->params_num); + wll (t->params_types); +} + +int is_builtin_type (const char *id) { + return !strcmp (id, "int") || !strcmp (id, "long") || !strcmp (id, "double") || !strcmp (id, "string") + || !strcmp(id, "object") || !strcmp(id, "function"); +} + +void write_combinator (struct tl_constructor *c) { + wint (c->name); + wstr (c->id); + wint (c->type ? c->type->name : 0); + struct tree_var_value *T = 0; + int x = 0; + assert (c->right); + if (c->left) { + if (is_builtin_type (c->id)) { + wint (TLS_COMBINATOR_LEFT_BUILTIN); + } else { + wint (TLS_COMBINATOR_LEFT); + // FIXME: What is that? +// wint (count_list_size (c->left)); + write_tree (c->left, 0, &T, &x); + } + } else { + wint (TLS_COMBINATOR_LEFT); + wint (0); + } + wint (TLS_COMBINATOR_RIGHT_V2); + write_tree (c->right, 1, &T, &x); +} + +void write_constructor (struct tl_constructor *c) { + wint (TLS_COMBINATOR); + write_combinator (c); +} + +void write_function (struct tl_constructor *c) { + wint (TLS_COMBINATOR); + write_combinator (c); +} + +void write_type_constructors (struct tl_type *t) { + int i; + for (i = 0; i < t->constructors_num; i++) { + write_constructor (t->constructors[i]); + } +} + +void write_types (FILE *f) { + __f = f; + wint (TLS_SCHEMA_V2); + wint (0); +#ifdef TL_PARSER_NEED_TIME + wint (time (0)); +#else + /* Make the tlo reproducible by default. Rationale: https://wiki.debian.org/ReproducibleBuilds/Howto#Introduction */ + wint (0); +#endif + num = 0; + wint (total_types_num); + tree_act_tl_type (tl_type_tree, write_type); + wint (total_constructors_num); + tree_act_tl_type (tl_type_tree, write_type_constructors); + wint (total_functions_num); + tree_act_tl_constructor (tl_function_tree, write_function); +} diff --git a/td/generate/tl-parser/tl-parser.h b/td/generate/tl-parser/tl-parser.h new file mode 100644 index 000000000..59209d4a5 --- /dev/null +++ b/td/generate/tl-parser/tl-parser.h @@ -0,0 +1,223 @@ +/* + This file is part of tgl-libary/tlc + + Tgl-library/tlc 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. + + Tgl-library/tlc 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 tgl-library/tlc. If not, see . + + Copyright Vitaly Valtman 2014 + + It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) + Copyright 2012-2013 Vkontakte Ltd + 2012-2013 Vitaliy Valtman + +*/ + +#ifndef __TL_PARSER_NEW_H__ +#define __TL_PARSER_NEW_H__ + +#include + +enum lex_type { + lex_error, + lex_char, + lex_triple_minus, + lex_uc_ident, + lex_lc_ident, + lex_eof, + lex_final, + lex_new, + lex_none, + lex_num, + lex_empty +}; + + +struct curlex { + char *ptr; + int len; + enum lex_type type; + int flags; +}; + +struct parse { + char *text; + int pos; + int len; + int line; + int line_pos; + struct curlex lex; +}; + + +enum tree_type { + type_tl_program, + type_fun_declarations, + type_constr_declarations, + type_declaration, + type_combinator_decl, + type_equals, + type_partial_app_decl, + type_final_decl, + type_full_combinator_id, + type_opt_args, + type_args, + type_args1, + type_args2, + type_args3, + type_args4, + type_boxed_type_ident, + type_subexpr, + type_partial_comb_app_decl, + type_partial_type_app_decl, + type_final_new, + type_final_final, + type_final_empty, +// type_type, + type_var_ident, + type_var_ident_opt, + type_multiplicity, + type_type_term, + type_term, + type_percent, + type_result_type, + type_expr, + type_nat_term, + type_combinator_id, + type_nat_const, + type_type_ident, + type_builtin_combinator_decl, + type_exclam, + type_optional_arg_def +}; + +struct tree { + char *text; + int len; + enum tree_type type; + int lex_line; + int lex_line_pos; + int flags; + int size; + int nc; + struct tree **c; +}; + + +#define TL_ACT(x) (x == act_var ? "act_var" : x == act_field ? "act_field" : x == act_plus ? "act_plus" : x == act_type ? "act_type" : x == act_nat_const ? "act_nat_const" : x == act_array ? "act_array" : x == act_question_mark ? "act_question_mark" : \ + x == act_union ? "act_union" : x == act_arg ? "act_arg" : x == act_opt_field ? "act_opt_field" : "act_unknown") + +#define TL_TYPE(x) (x == type_num ? "type_num" : x == type_type ? "type_type" : x == type_list_item ? "type_list_item" : x == type_list ? "type_list" : x == type_num_value ? "type_num_value" : "type_unknown") +enum combinator_tree_action { + act_var, + act_field, + act_plus, + act_type, + act_nat_const, + act_array, + act_question_mark, + act_union, + act_arg, + act_opt_field +}; + +enum combinator_tree_type { + type_num, + type_num_value, + type_type, + type_list_item, + type_list +}; + +struct tl_combinator_tree { + enum combinator_tree_action act; + struct tl_combinator_tree *left, *right; + char *name; + void *data; + long long flags; + enum combinator_tree_type type; + int type_len; + long long type_flags; +}; + + +struct tl_program { + int types_num; + int functions_num; + int constructors_num; + struct tl_type **types; + struct tl_function **functions; +// struct tl_constuctor **constructors; +}; + +struct tl_type { + char *id; + char *print_id; + char *real_id; + unsigned name; + int flags; + + int params_num; + long long params_types; + + int constructors_num; + struct tl_constructor **constructors; +}; + +struct tl_constructor { + char *id; + char *print_id; + char *real_id; + unsigned name; + struct tl_type *type; + + struct tl_combinator_tree *left; + struct tl_combinator_tree *right; +}; + +struct tl_var { + char *id; + struct tl_combinator_tree *ptr; + int type; + int flags; +}; + +struct parse *tl_init_parse_file (const char *fname); +struct tree *tl_parse_lex (struct parse *P); +void tl_print_parse_error (void); +struct tl_program *tl_parse (struct tree *T); + +void write_types (FILE *f); + +#define FLAG_BARE 1 +#define FLAG_OPT_VAR (1 << 17) +#define FLAG_EXCL (1 << 18) +#define FLAG_OPT_FIELD (1 << 20) +#define FLAG_IS_VAR (1 << 21) +#define FLAG_DEFAULT_CONSTRUCTOR (1 << 25) +#define FLAG_EMPTY (1 << 10) + +#ifdef NDEBUG +#undef assert +#define assert(x) if (!(x)) { fprintf(stderr, "Assertion error!\n"); abort(); } +#endif + +#ifdef _WIN32 +#include "wgetopt.h" + +#define __attribute__(x) + +#define lrand48() rand() +#define strdup _strdup +#endif + +#endif diff --git a/td/generate/tl-parser/tl-tl.h b/td/generate/tl-parser/tl-tl.h new file mode 100644 index 000000000..8bc0a707b --- /dev/null +++ b/td/generate/tl-parser/tl-tl.h @@ -0,0 +1,55 @@ +/* + This file is part of VK/KittenPHP-DB-Engine. + + VK/KittenPHP-DB-Engine 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. + + VK/KittenPHP-DB-Engine 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 VK/KittenPHP-DB-Engine. If not, see . + + This program is released under the GPL with the additional exemption + that compiling, linking, and/or using OpenSSL is allowed. + You are free to remove this exemption from derived works. + + Copyright 2012-2013 Vkontakte Ltd + 2012-2013 Vitaliy Valtman +*/ + +#ifndef __TL_TL_H__ +#define __TL_TL_H__ + +// Current tl-tl schema is V2 +// See https://core.telegram.org/mtproto/TL-tl + +#define TLS_SCHEMA_V2 0x3a2f9be2 +#define TLS_TYPE 0x12eb4386 +#define TLS_COMBINATOR 0x5c0a1ed5 +#define TLS_COMBINATOR_LEFT_BUILTIN 0xcd211f63 +#define TLS_COMBINATOR_LEFT 0x4c12c6d9 +#define TLS_COMBINATOR_RIGHT_V2 0x2c064372 +#define TLS_ARG_V2 0x29dfe61b + +#define TLS_EXPR_TYPE 0xecc9da78 +#define TLS_EXPR_NAT 0xdcb49bd8 + +#define TLS_NAT_CONST 0xdcb49bd8 +#define TLS_NAT_VAR 0x4e8a14f0 +#define TLS_TYPE_VAR 0x0142ceae +#define TLS_ARRAY 0xd9fb20de +#define TLS_TYPE_EXPR 0xc1863d08 + +/* Deprecated (old versions), read-only */ +#define TLS_TREE_NAT_CONST 0xc09f07d7 +#define TLS_TREE_NAT_VAR 0x90ea6f58 +#define TLS_TREE_TYPE_VAR 0x1caa237a +#define TLS_TREE_ARRAY 0x80479360 +#define TLS_TREE_TYPE 0x10f32190 + +#endif diff --git a/td/generate/tl-parser/tlc.c b/td/generate/tl-parser/tlc.c new file mode 100644 index 000000000..faddf9400 --- /dev/null +++ b/td/generate/tl-parser/tlc.c @@ -0,0 +1,165 @@ +/* + This file is part of tl-parser + + tl-parser 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. + + tl-parser 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 tl-parser. If not, see . + + Copyright Vitaly Valtman 2014 + + It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) + Copyright 2012-2013 Vkontakte Ltd + 2012-2013 Vitaliy Valtman + +*/ + +#include +#include +#include + +#include "tl-parser.h" + +#ifndef _WIN32 +#include +#endif + +#include +#include +#include + +#include + +#ifdef HAVE_EXECINFO_H +#include +#endif +#include + +int verbosity; +int output_expressions; +void usage (void) { + printf ("usage: tl-parser [-v] [-h] \n" + "\tTL compiler\n" + "\t-v\toutput statistical and debug information into stderr\n" + "\t-E\twhenever is possible output to stdout expressions\n" + "\t-e \texport serialized schema to file\n" + ); + exit (2); +} + +int vkext_write (const char *filename) { + FILE *f = fopen(filename, "wb"); + assert (f != NULL); + write_types (f); + fclose (f); + return 0; +} + +void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +void logprintf (const char *format __attribute__ ((unused)), ...) { + va_list ap; + va_start (ap, format); + vfprintf (stderr, format, ap); + va_end (ap); +} + +void hexdump (int *in_ptr, int *in_end) { + int *ptr = in_ptr; + while (ptr < in_end) { printf (" %08x", *(ptr ++)); } + printf ("\n"); +} + +#ifdef HAVE_EXECINFO_H +void print_backtrace (void) { + void *buffer[255]; + const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); + backtrace_symbols_fd (buffer, calls, 1); +} +#else +void print_backtrace (void) { + if (fwrite ("No libexec. Backtrace disabled\n", 32, 1, stderr) < 0) { + // Sad thing + } +} +#endif + +void sig_segv_handler (int signum __attribute__ ((unused))) { + if (fwrite ("SIGSEGV received\n", 18, 1, stderr) < 0) { + // Sad thing + } + print_backtrace (); + exit (EXIT_FAILURE); +} + +void sig_abrt_handler (int signum __attribute__ ((unused))) { + if (fwrite ("SIGABRT received\n", 18, 1, stderr) < 0) { + // Sad thing + } + print_backtrace (); + exit (EXIT_FAILURE); +} + +int main (int argc, char **argv) { + signal (SIGSEGV, sig_segv_handler); + signal (SIGABRT, sig_abrt_handler); + int i; + char *vkext_file = 0; + while ((i = getopt (argc, argv, "Ehve:w:")) != -1) { + switch (i) { + case 'E': + output_expressions++; + break; + case 'h': + usage (); + return 2; + case 'e': + vkext_file = optarg; + break; + case 'v': + verbosity++; + break; + } + } + + if (argc != optind + 1) { + usage (); + } + + + struct parse *P = tl_init_parse_file (argv[optind]); + if (!P) { + return 1; + } + struct tree *T; + if (!(T = tl_parse_lex (P))) { + fprintf (stderr, "Error in parse:\n"); + tl_print_parse_error (); + return 1; + } else { + if (verbosity) { + fprintf (stderr, "Parse ok\n"); + } + if (!tl_parse (T)) { + if (verbosity) { + fprintf (stderr, "Fail\n"); + } + return 1; + } else { + if (verbosity) { + fprintf (stderr, "Ok\n"); + } + } + } + if (vkext_file) { + vkext_write (vkext_file); + } + return 0; +} diff --git a/td/generate/tl-parser/wgetopt.c b/td/generate/tl-parser/wgetopt.c new file mode 100644 index 000000000..4557b9211 --- /dev/null +++ b/td/generate/tl-parser/wgetopt.c @@ -0,0 +1,1274 @@ +/* Getopt for GNU. +NOTE: getopt is now part of the C library, so if you don't know what +"Keep this file name-space clean" means, talk to drepper@gnu.org +before changing it! +Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 +Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +The GNU C Library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with the GNU C Library; if not, write to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . +Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems +reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not +actually compiling the library itself. This code is part of the GNU C +Library, but also included in many other GNU distributions. Compiling +and linking in this code is a waste when using the GNU C library +(especially if it is a shared library). Rather than having every GNU +program understand `configure --with-gnu-libc' and omit the object files, +it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include +to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them +contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. */ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# ifndef _ +# define _(msgid) gettext (msgid) +# endif +# else +# define _(msgid) (msgid) +# endif +# if defined _LIBC && defined USE_IN_LIBIO +# include +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' +but it behaves differently for the user, since it allows the user +to intersperse the options with the other arguments. + +As `getopt' works, it permutes the elements of ARGV so that, +when it is done, all the options precede everything else. Thus +all application programs are extended to handle flexible argument order. + +Setting the environment variable POSIXLY_CORRECT disables permutation. +Then the behavior is completely standard. + +GNU application programs can use a third alternative mode in which +they can distinguish the relative order of options and other arguments. */ + +#include "wgetopt.h" + +/* For communication from `getopt' to the caller. +When `getopt' finds an option that takes an argument, +the argument value is returned here. +Also, when `ordering' is RETURN_IN_ORDER, +each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. +This is used for communication to and from the caller +and for communication between successive calls to `getopt'. + +On entry to `getopt', zero means this is the first call; initialize. + +When `getopt' returns -1, this is the index of the first of the +non-option elements that the caller should itself scan. + +Otherwise, `optind' communicates from one call to the next +how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which +causes problems with re-calling getopt as programs generally don't +know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element +in which the last option character we returned was found. +This allows us to pick up the scan where we left off. + +If this is zero, or a null string, it means resume the scan +by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message +for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. +This must be initialized on some systems to avoid linking in the +system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + +If the caller did not specify anything, +the default is REQUIRE_ORDER if the environment variable +POSIXLY_CORRECT is defined, PERMUTE otherwise. + +REQUIRE_ORDER means don't recognize them as options; +stop option processing when the first non-option is seen. +This is what Unix does. +This mode of operation is selected by either setting the environment +variable POSIXLY_CORRECT, or using `+' as the first character +of the list of option characters. + +PERMUTE is the default. We permute the contents of ARGV as we scan, +so that eventually all the non-options are at the end. This allows options +to be given in any order, even with programs that were not written to +expect this. + +RETURN_IN_ORDER is an option available to programs that were written +to expect options and other ARGV-elements in any order and that care about +the ordering of the two. We describe each non-option ARGV-element +as if it were the argument of an option with character code 1. +Using `-' as the first character of the list of option characters +selects this mode of operation. + +The special argument `--' forces an end of option-scanning regardless +of the value of `ordering'. In the case of RETURN_IN_ORDER, only +`--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries +because there are many ways it can cause trouble. +On some systems, it contains special magic macros that don't work +in GCC. */ +# include +# define my_index strchr +#else + +#define HAVE_STRING_H 1 +# if HAVE_STRING_H +# include +# else +# include +# endif + +/* Avoid depending on library functions or files +whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv(); +#endif + +static char * +my_index(str, chr) +const char *str; +int chr; +{ + while (*str) + { + if (*str == chr) + return (char *)str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. +If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. +That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, +and has done so at least since version 2.4.5. -- rms. */ +extern int strlen(const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have +been skipped. `first_nonopt' is the index in ARGV of the first of them; +`last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Stored original parameters. +XXX This is no good solution. We should rather copy the args so +that we can compare them later. But we must not use malloc(3). */ +extern int __libc_argc; +extern char **__libc_argv; + +/* Bash 2.0 gives us an environment variable containing flags +indicating ARGV elements that should not be considered arguments. */ + +# ifdef USE_NONOPTION_FLAGS +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; +# endif + +# ifdef USE_NONOPTION_FLAGS +# define SWAP_FLAGS(ch1, ch2) \ +if (nonoption_flags_len > 0) \ +{ \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ +} +# else +# define SWAP_FLAGS(ch1, ch2) +# endif +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. +One subsequence is elements [first_nonopt,last_nonopt) +which contains all the non-options that have been skipped so far. +The other is elements [last_nonopt,optind), which contains all +the options processed since those non-options were skipped. + +`first_nonopt' and `last_nonopt' are relocated so that they describe +the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange(char **); +#endif + +static void +exchange(argv) +char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc(top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset(__mempcpy(new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS(bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize(int, char *const *, const char *); +#endif +static const char * +_getopt_initialize(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + if (posixly_correct == NULL + && argc == __libc_argc && argv == __libc_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen(orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *)malloc(nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters +given in OPTSTRING. + +If an element of ARGV starts with '-', and is not exactly "-" or "--", +then it is an option element. The characters of this element +(aside from the initial '-') are option characters. If `getopt' +is called repeatedly, it returns successively each of the option characters +from each of the option elements. + +If `getopt' finds another option character, it returns that character, +updating `optind' and `nextchar' so that the next call to `getopt' can +resume the scan with the following option character or ARGV-element. + +If there are no more option characters, `getopt' returns -1. +Then `optind' is the index in ARGV of the first ARGV-element +that is not an option. (The ARGV-elements have been permuted +so that those that are not options now come last.) + +OPTSTRING is a string containing the legitimate option characters. +If an option character is seen that is not listed in OPTSTRING, +return '?' after printing an error message. If you set `opterr' to +zero, the error message is suppressed but we still return '?'. + +If a char in OPTSTRING is followed by a colon, that means it wants an arg, +so the following text in the same ARGV-element, or the text of the following +ARGV-element, is returned in `optarg'. Two colons mean an option that +wants an optional arg; if there is text in the current ARGV-element, +it is returned in `optarg', otherwise `optarg' is set to zero. + +If OPTSTRING starts with `-' or `+', it requests different methods of +handling the non-option ARGV-elements. +See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + +Long-named options begin with `--' instead of `-'. +Their names may be abbreviated as long as the abbreviation is unique +or is an exact match for some defined option. If they have an +argument, it follows the option name in the same ARGV-element, separated +from the option name by a `=', or else the in next ARGV-element. +When `getopt' finds a long-named option, it returns 0 if that option's +`flag' field is nonzero, the value of the option's `val' field +if the `flag' field is zero. + +The elements of ARGV aren't really const, because we permute them. +But we pretend they're const in the prototype to be compatible +with other systems. + +LONGOPTS is a vector of `struct option' terminated by an +element containing a name which is zero. + +LONGIND returns the index in LONGOPT of the long-named option found. +It is only valid when a long-named option has been found by the most +recent call. + +If LONG_ONLY is nonzero, '-' as well as '--' can introduce +long-named options. */ + +int +_getopt_internal(argc, argv, optstring, longopts, longind, long_only) +int argc; +char *const *argv; +const char *optstring; +const struct option *longopts; +int *longind; +int long_only; +{ + int print_errors = opterr; + if (optstring[0] == ':') + print_errors = 0; + + if (argc < 1) + return -1; + + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize(argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#if defined _LIBC && defined USE_NONOPTION_FLAGS +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange((char **)argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp(argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange((char **)argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int)(nameend - nextchar) + == (unsigned int)strlen(p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); +#endif + } + nextchar += strlen(nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; +#endif + + if (argv[optind - 1][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("\ + %s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#else + fprintf(stderr, _("\ + %s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("\ + %s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], + pfound->name); +#else + fprintf(stderr, _("\ + %s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#endif + } + + nextchar += strlen(nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); +#endif + } + nextchar += strlen(nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index(optstring, *nextchar) == NULL) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; +#endif + + if (argv[optind][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); +#else + fprintf(stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); +#else + fprintf(stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#endif + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index(optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; +#endif + + if (posixly_correct) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: illegal option -- %c\n"), + argv[0], c); +#else + fprintf(stderr, _("%s: illegal option -- %c\n"), argv[0], c); +#endif + } + else + { +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: invalid option -- %c\n"), + argv[0], c); +#else + fprintf(stderr, _("%s: invalid option -- %c\n"), argv[0], c); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#endif + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("%s: option requires an argument -- %c\n"), + argv[0], c); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int)(nameend - nextchar) == strlen(p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); +#endif + } + nextchar += strlen(nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("\ + %s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("\ + %s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + + nextchar += strlen(nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("\ + %s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); +#endif + } + nextchar += strlen(nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; +{ + return _getopt_internal(argc, argv, optstring, + (const struct option *) 0, + (int *)0, + 0); +} + + + + +int +getopt_long(int argc, char *const *argv, const char *options, +const struct option *long_options, int *opt_index) +{ + return _getopt_internal(argc, argv, options, long_options, opt_index, 0, 0); +} + +int +getopt_long_only(int argc, char *const *argv, const char *options, +const struct option *long_options, int *opt_index) +{ + return _getopt_internal(argc, argv, options, long_options, opt_index, 1, 0); +} + + + + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing +the above definition of `getopt'. */ + +int +main(argc, argv) +int argc; +char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt(argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf("option %c\n", c); + break; + + case 'a': + printf("option a\n"); + break; + + case 'b': + printf("option b\n"); + break; + + case 'c': + printf("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf("non-option ARGV-elements: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + } + + exit(0); +} + +#endif /* TEST */ diff --git a/td/generate/tl-parser/wgetopt.h b/td/generate/tl-parser/wgetopt.h new file mode 100644 index 000000000..6e2fa2718 --- /dev/null +++ b/td/generate/tl-parser/wgetopt.h @@ -0,0 +1,193 @@ +/* Declarations for getopt. + Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2009,2010 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +/* If __GNU_LIBRARY__ is not already defined, either we are being used + standalone, or this is the first header included in the source file. + If we are being used with glibc, we need to include , but + that does not exist if we are standalone. So: if __GNU_LIBRARY__ is + not defined, include , which will pull in for us + if it's from glibc. (Why ctype.h? It's guaranteed to exist and it + doesn't flood the namespace with stuff the way some other headers do.) */ +#if !defined __GNU_LIBRARY__ +# include +#endif + +#ifndef __THROW +# ifndef __GNUC_PREREQ +# define __GNUC_PREREQ(maj, min) (0) +# endif +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# else +# define __THROW +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) + __THROW; + +# if defined __need_getopt && defined __USE_POSIX2 \ + && !defined __USE_POSIX_IMPLICITLY && !defined __USE_GNU +/* The GNU getopt has more functionality than the standard version. The + additional functionality can be disable at runtime. This redirection + helps to also do this at runtime. */ +# ifdef __REDIRECT + extern int __REDIRECT_NTH (getopt, (int ___argc, char *const *___argv, + const char *__shortopts), + __posix_getopt); +# else +extern int __posix_getopt (int ___argc, char *const *___argv, + const char *__shortopts) __THROW; +# define getopt __posix_getopt +# endif +# endif +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ + +#ifndef __need_getopt +extern int getopt_long (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; +extern int getopt_long_only (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; + +#endif + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */