diff options
| author | Nagi5Yeq <wu@x-nagi.com> | 2020-05-12 01:52:49 +0800 |
|---|---|---|
| committer | Nagi5Yeq <wu@x-nagi.com> | 2020-05-12 01:52:49 +0800 |
| commit | f146dac784325c9403499046f52f70e3596ae345 (patch) | |
| tree | 4af8b76cbf83892d3cbfdda7a4b17fa8af34b4a0 | |
initial commit
| -rw-r--r-- | .clang-format | 36 | ||||
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | CMakeLists.txt | 41 | ||||
| -rw-r--r-- | COPYING | 340 | ||||
| -rw-r--r-- | Context.cc | 11 | ||||
| -rw-r--r-- | Context.hh | 22 | ||||
| -rw-r--r-- | Driver.cc | 21 | ||||
| -rw-r--r-- | Driver.hh | 28 | ||||
| -rwxr-xr-x | Lexer.l | 198 | ||||
| -rw-r--r-- | Log.cc | 31 | ||||
| -rw-r--r-- | Log.hh | 17 | ||||
| -rw-r--r-- | Parser.y | 247 | ||||
| -rw-r--r-- | Version.cc | 31 | ||||
| -rw-r--r-- | Version.hh | 27 | ||||
| -rw-r--r-- | getopt.c | 223 | ||||
| -rw-r--r-- | getopt.h | 59 | ||||
| -rw-r--r-- | main.cc | 40 | ||||
| -rw-r--r-- | node/BaseNode.cc | 6 | ||||
| -rw-r--r-- | node/BaseNode.hh | 21 | ||||
| -rw-r--r-- | node/LiteralNode.cc | 22 | ||||
| -rw-r--r-- | node/LiteralNode.hh | 17 | ||||
| -rw-r--r-- | t/1.pas | 17 |
22 files changed, 1457 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..497ab0b --- /dev/null +++ b/.clang-format @@ -0,0 +1,36 @@ +#基于哪个配置文件 +BasedOnStyle: LLVM +#指针的*的挨着哪边 +PointerAlignment: Left +#缩进宽度 +IndentWidth: 4 +#连续的空行保留几行 +MaxEmptyLinesToKeep: 1 +#是否允许短方法单行 +AllowShortFunctionsOnASingleLine: true +#是否允许短if单行 If true, if (a) return; 可以放到同一行 +AllowShortIfStatementsOnASingleLine: true +#注释对齐 +AlignTrailingComments: true +#换行的时候对齐操作符 +#AlignOperands: true +#多行声明语句按照=对齐 +AlignConsecutiveDeclarations: true +#连续的赋值语句以 = 为中心对齐 +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +#等号两边的空格 +SpaceBeforeAssignmentOperators: true +#缩进 +IndentWrappedFunctionNames: true +#在block从空行开始 +KeepEmptyLinesAtTheStartOfBlocks: true +#在构造函数初始化时按逗号断行,并以冒号对齐 +BreakConstructorInitializersBeforeComma: true +#函数参数换行 +AllowAllParametersOfDeclarationOnNextLine: true +#括号后添加空格 +SpaceAfterCStyleCast: true +#tab键盘的宽度 +TabWidth: 4 +UseTab: Never diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5acb669 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..473eb3d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.4) +project(pcc) + +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) + +find_package(BISON REQUIRED) +find_package(FLEX REQUIRED) + +bison_target(pcc_parser Parser.y ${CMAKE_CURRENT_BINARY_DIR}/Parser.cc) +flex_target(pcc_lexer Lexer.l ${CMAKE_CURRENT_BINARY_DIR}/Lexer.cc) +add_flex_bison_dependency(pcc_lexer pcc_parser) + +add_definitions(-DPCC_OSNAME="${CMAKE_SYSTEM}") + +set(PCC_SOURCE + Context.cc + Driver.cc + Lexer.cc + Log.cc + main.cc + Parser.cc + Version.cc) + +list(APPEND PCC_SOURCE + node/BaseNode.cc + node/LiteralNode.cc) + +list(APPEND PCC_SOURCE + ${BISON_pcc_parser_OUTPUT} + ${FLEX_pcc_lexer_OUTPUT}) + +add_executable(pcc ${PCC_SOURCE}) +target_include_directories(pcc PRIVATE + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/node + ${CMAKE_CURRENT_BINARY_DIR}) + +llvm_map_components_to_libnames(llvm_libs support core irreader all) +target_link_libraries(pcc ${llvm_libs}) @@ -0,0 +1,340 @@ + 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 Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Context.cc b/Context.cc new file mode 100644 index 0000000..ee88544 --- /dev/null +++ b/Context.cc @@ -0,0 +1,11 @@ +#include <llvm/IR/LLVMContext.h> + +#include "Context.hh" + +namespace pcc { +llvm::LLVMContext GlobalContext; + +Context::Context(const char* name) + : builder_(GlobalContext) + , module_(name, GlobalContext) {} +} // namespace pcc diff --git a/Context.hh b/Context.hh new file mode 100644 index 0000000..bc66632 --- /dev/null +++ b/Context.hh @@ -0,0 +1,22 @@ +#ifndef PCC_CONTEXT_H +#define PCC_CONTEXT_H + +#include <llvm/IR/IRBuilder.h> +#include <llvm/IR/Module.h> + +namespace pcc { +class Driver; +class Context { + public: + Context(const char* name); + + private: + llvm::IRBuilder<> builder_; + llvm::Module module_; + friend class Driver; +}; + +extern llvm::LLVMContext GlobalContext; +} // namespace pcc + +#endif diff --git a/Driver.cc b/Driver.cc new file mode 100644 index 0000000..3fefd8c --- /dev/null +++ b/Driver.cc @@ -0,0 +1,21 @@ +#include "Driver.hh" + +namespace pcc { +Driver::Driver(Context* context) + : context_(context) {} + +Driver::~Driver() {} + +void Driver::Parse(const std::string& filename) { + if (StartLexer(filename) != 0) { + return; + } + Parser parser(*this); + parser.parse(); + StopLexer(); +} + +llvm::Module* Driver::GetModule() { return &context_->module_; } + +llvm::IRBuilder<>* Driver::GetBuilder() { return &context_->builder_; } +} // namespace pcc diff --git a/Driver.hh b/Driver.hh new file mode 100644 index 0000000..5fc5d83 --- /dev/null +++ b/Driver.hh @@ -0,0 +1,28 @@ +#ifndef PCC_DRIVER_H +#define PCC_DRIVER_H + +#include <cstdio> + +#include "Context.hh" +#include "Parser.hh" + +#define YY_DECL pcc::Parser::symbol_type yylex(pcc::Driver& driver) + +YY_DECL; + +namespace pcc { +class Driver { + public: + Driver(Context* context); + ~Driver(); + int StartLexer(const std::string& filename); + void StopLexer(); + void Parse(const std::string& filename); + llvm::Module* GetModule(); + llvm::IRBuilder<>* GetBuilder(); + + Context* context_; +}; +} // namespace pcc + +#endif @@ -0,0 +1,198 @@ +%{ +#include <map> +#include <cctype> +#include <cstdlib> +#include <iostream> +#include <algorithm> + +#include "Log.hh" +#include "Driver.hh" + +using token=pcc::Parser::token; + +namespace pcc { + class Lexer; + char ToLower(char c){ + return static_cast<char>(std::tolower(static_cast<unsigned char>(c))); + } +} + +%} + +%option nodefault +%option never-interactive +%option nounistd +%option case-insensitive +%option noyywrap nounput noinput + +decimal ([1-9][0-9]*)|0 +octal 0[0-7]* +hexadecimal 0[xX][0-9a-fA-F] + +integer [+-]?({decimal}|{octal}|{hexadecimal}) + +real_exp [0-9]*(\.[0-9]*)?[eE]{decimal} +real_noexp [0-9]*\.[0-9]* + +real [+-]?({real_exp}|{real_noexp}) + +char [0-9a-zA-Z_{}[\]#()<>%:;.?*+\-/^&|~!=,\\" \t\n\v\f] +escaped_char \\[\'?\\abfnrtv] +hex_char \\x[0-9a-fA-F]{1,2} +oct_char \\[0-7]{1,3} + +string '({char}|{escaped_char}|{hex_char}|{oct_char}|\\')*' + +identifier [a-z][0-9a-z]* + +white [\t\f\n\r ] + +%% + +":=" {return token::ASSIGN;} +":" {return token::COLON;} +";" {return token::SEMICOLON;} +"." {return token::DOT;} +"[" {return token::LBRACKET;} +"]" {return token::RBRACKET;} +"(" {return token::LPARENTHESIS;} +")" {return token::RPARENTHESIS;} + +"+" {return token::ADD;} +"-" {return token::SUB;} +"*" {return token::MUL;} +"/" {return token::REAL_DIV;} +"div" {return token::DIV;} +"mod" {return token::MOD;} +"**" {return token::EXP;} + +"and" {return token::AND;} +"not" {return token::NOT;} +"or" {return token::OR;} +"xor" {return token::XOR;} + +"<" {return token::LT;} +"<=" {return token::LE;} +">" {return token::GT;} +">=" {return token::GE;} +"=" {return token::EQ;} +"<>" {return token::NE;} + +"begin" {return token::BEGINS;} +"end" {return token::ENDS;} +"program" {return token::PROGRAM;} +"function" {return token::FUNCTION;} +"const" {return token::CONST;} +"var" {return token::VAR;} +"if" {return token::IF;} +"then" {return token::THEN;} +"else" {return token::ELSE;} +"while" {return token::WHILE;} +"do" {return token::DO;} +"integer" {return token::INTEGER;} +"boolean" {return token::BOOLEAN;} +"char" {return token::CHAR;} +"real" {return token::REAL;} +"string" {return token::STRING;} +"true" {return token::TRUE;} +"false" {return token::FALSE;} + +{integer} { + int number = std::strtol(yytext, NULL, 0); + return pcc::Parser::make_INTEGER_LITERAL(number); +} + +{real} { + float number = std::strtof(yytext, NULL); + return pcc::Parser::make_REAL_LITERAL(number); +} + +{string} { + static std::map<char,char> escape_map={ + {'\'','\''}, + {'?','\?'}, + {'\\','\\'}, + {'a','\a'}, + {'b','\b'}, + {'f','\f'}, + {'n','\n'}, + {'r','\r'}, + {'t','\t'}, + {'v','\v'} + }; + char *str = new char[yyleng]; + char *p = str; + int i = 1; + while(i<yyleng-1){ + if(yytext[i]!='\\'){ + *p++=yytext[i]; + i++; + } + else if(yytext[i+1]=='x'){ + char c[3], *cend; + c[0]=yytext[i+2]; + if(i+3<yyleng-1){ + c[1]=yytext[i+3]; + c[2]='\0'; + } else { + c[1]='\0'; + } + *p++=(char)std::strtol(c,&cend,16); + i+=(int)(cend-c)+2; + } + else if(yytext[i+1]>='0' && yytext[i+1]<='7'){ + char c[4], *cend; + c[0]=yytext[i+1]; + if(i+3<yyleng-1){ + c[1]=yytext[i+2]; + c[2]=yytext[i+3]; + c[3]='\0'; + } + else if(i+3<yyleng){ + c[1]=yytext[i+2]; + c[2]='\0'; + } + else { + c[1]='\0'; + } + *p++=(char)std::strtol(c,&cend,8); + i+=(int)(cend-c)+1; + } + else { + *p++=escape_map[yytext[i+1]]; + i+=2; + } + } + *p++='\0'; + return pcc::Parser::make_STRING_LITERAL(str); +} + +{identifier} { + char *name = new char[yyleng]; + std::transform(yytext, yytext+yyleng, name, pcc::ToLower); + return pcc::Parser::make_IDENTIFIER(yytext); +} + +{white} {} + +. { + std::cerr<<"ERROR"; +} + +%% + +namespace pcc { + int Driver::StartLexer(const std::string &filename) + { + yyin=std::fopen(filename.c_str(),"r"); + if(yyin==NULL){ + Log(PCC_ERROR, "Failed to open file %s", filename.c_str()); + return -1; + } + return 0; + } + + void Driver::StopLexer(){ + std::fclose(yyin); + } +} @@ -0,0 +1,31 @@ +#include "Log.hh" + +namespace pcc { +void Log(LogLevel level, const char* format, ...) { + va_list va; + va_start(va, format); + if (CurrentLogLevel <= level) { + switch (level) { + case PCC_ERROR: + fprintf(stderr, "[ERROR] "); + break; + case PCC_WARNING: + fprintf(stderr, "[WARNING] "); + break; + case PCC_INFO: + fprintf(stderr, "[INFO] "); + break; + case PCC_DEBUG: + fprintf(stderr, "[DEBUG] "); + break; + } + std::vfprintf(stderr, format, va); + std::fputc('\n', stderr); + } + va_end(va); +} + +LogLevel CurrentLogLevel = PCC_ERROR; + +void SetLogLevel(LogLevel level) { CurrentLogLevel = level; } +} // namespace pcc @@ -0,0 +1,17 @@ +#ifndef PCC_LOG_H +#define PCC_LOG_H + +#include <cstdarg> +#include <cstdio> + +namespace pcc { +enum LogLevel { PCC_ERROR, PCC_WARNING, PCC_INFO, PCC_DEBUG }; + +extern LogLevel CurrentLogLevel; + +void SetLogLevel(LogLevel level); + +void Log(LogLevel level, const char* format, ...); +} // namespace pcc + +#endif diff --git a/Parser.y b/Parser.y new file mode 100644 index 0000000..bbad3fb --- /dev/null +++ b/Parser.y @@ -0,0 +1,247 @@ +%language "c++" +%require "3.2" + +%code requires { +#include <string> + +namespace pcc { + class Driver; +} +} + +%param {pcc::Driver& driver} + +%code { +#include "Driver.hh" +} + +%define api.namespace {pcc} +%define api.parser.class {Parser} +%define api.value.type variant +%define api.token.constructor +%define parse.error verbose +%define parse.assert + +%token COLON SEMICOLON COMMA DOT ASSIGN LBRACKET RBRACKET LPARENTHESIS RPARENTHESIS +%token PROGRAM IDENTIFIER CONST VAR BEGINS ENDS FUNCTION +%token IF THEN ELSE WHILE DO +%token INTEGER BOOLEAN CHAR REAL STRING +%token ADD SUB MUL REAL_DIV DIV MOD EXP LT LE GT GE EQ NE +%token AND NOT OR XOR TRUE FALSE +%token INTEGER_LITERAL REAL_LITERAL STRING_LITERAL + +%type <int> INTEGER_LITERAL +%type <float> REAL_LITERAL +%type <char*> STRING_LITERAL +%type <char*> IDENTIFIER + +%% + +/* ==================[global part]================== */ + +program + : program_decl global_decls function_decls + ; + +program_decl + : PROGRAM IDENTIFIER SEMICOLON + ; + +global_decls + : var_block + ; + +function_decls + : function_decls function_decl + | + ; + +/* ==================[var part]================== */ + +var_block + : VAR var_decls SEMICOLON + ; + +var_decls + : var_decls SEMICOLON var_decl + | var_decl + ; + +var_decl + : vars COLON var_type + ; + +vars + : vars COMMA IDENTIFIER + | IDENTIFIER + +var_type + : INTEGER + | REAL + | BOOLEAN + | CHAR + | STRING + ; + +/* ==================[function part]================== */ + +function_decl + : function_header function_body + ; + +function_header + : FUNCTION IDENTIFIER LPARENTHESIS var_decls RPARENTHESIS COLON var_type SEMICOLON + ; + +function_body + : var_block statement_block SEMICOLON + | statement_block SEMICOLON + ; + +/* ==================[statements part]================== */ + +statements + : statements statement SEMICOLON + | + ; + +statement + : closed_statement + | open_statement + ; + +open_statement + : IF expression THEN statement + | IF expression THEN closed_statement ELSE open_statement + ; + +closed_statement + : normal_statement + | IF expression THEN closed_statement ELSE closed_statement + ; + +normal_statement + : statement_block + | empty_statement + | assign_statement + | while_statement + | expression_statement + ; + +statement_block + : BEGINS statements ENDS + ; + +empty_statement + : + ; + +assign_statement + : lvalue ASSIGN expression + ; + +while_statement + : WHILE expression DO statement + ; + +expression_statement + : function_call + ; + +/* ==================[expression part]================== */ + +expression + : l1_expression l1_operator expression + | l1_expression + ; + +l1_expression + : l1_expression l2_operator l2_expression + | l2_expression + ; + +l2_expression + : l2_expression l3_operator l3_expression + | l3_expression + ; + +l3_expression + : l3_expression l4_operator l4_expression + | l4_expression + +l4_expression + : lvalue + | function_call + | literal + | LPARENTHESIS expression RPARENTHESIS + | l5_operator l4_expression + ; + +l1_operator + : LT + | LE + | GT + | GE + | EQ + | NE + ; + +l2_operator + : ADD + | SUB + | OR + | XOR + ; + +l3_operator + : MUL + | REAL_DIV + | DIV + | MOD + | AND + ; + +l4_operator + : EXP + ; + +l5_operator + : NOT + | ADD + | SUB + ; + +lvalue + : IDENTIFIER + | IDENTIFIER LBRACKET expression RBRACKET + | IDENTIFIER DOT IDENTIFIER + ; + +function_call + : IDENTIFIER LPARENTHESIS arguments RPARENTHESIS + | IDENTIFIER LPARENTHESIS RPARENTHESIS + ; + +arguments + : arguments COMMA expression + | expression + ; + +literal + : TRUE + | FALSE + | INTEGER_LITERAL + | REAL_LITERAL + | STRING_LITERAL + ; + +%% + +namespace pcc { + + void Parser::error (const std::string& m) + { + std::cerr << m << '\n'; + } + +} diff --git a/Version.cc b/Version.cc new file mode 100644 index 0000000..9b8be86 --- /dev/null +++ b/Version.cc @@ -0,0 +1,31 @@ +#include "Version.hh" + +namespace pcc { + +PCC_NORETURN void ShowVersion() { + std::cerr + << PCC_NAME " version " PCC_VERSION_STRING "\n" + << "Copyright (C) 2020 Hanjie Wu <nagi@zju.edu.cn>\n" + "Platform: " PCC_OSNAME "\n" + "Built on " __DATE__ " " __TIME__ "\n\n" + "This program is free software; you can redistribute it and/or " + "modify\n" + "it under the terms of the GNU General Public License as published " + "by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version." + << std::endl; + std::exit(0); +} + +PCC_NORETURN void ShowHelp() { + std::cerr << PCC_NAME " version " PCC_VERSION_STRING "\n" + << "Usage: " PCC_NAME " [-vVh] file...\n" + << " -v Verbose mode.\n" + " -V Show version and exit.\n" + " -h Show this help and exit." + << std::endl; + std::exit(0); +} + +} // namespace pcc diff --git a/Version.hh b/Version.hh new file mode 100644 index 0000000..5b3a7ff --- /dev/null +++ b/Version.hh @@ -0,0 +1,27 @@ +#ifndef PCC_VERSION_H +#define PCC_VERSION_H + +#include <cstdlib> +#include <iostream> + +#define PCC_NAME "pcc" +#define PCC_VERSION_STRING "0.1.0" + +#ifndef PCC_OSNAME +#define PCC_OSNAME "unknown platform" +#endif + +#ifdef _MSC_VER +#define PCC_NORETURN __declspec(noreturn) +#else +#define PCC_NORETURN __attribute__((noreturn)) +#endif + +namespace pcc { + +PCC_NORETURN void ShowVersion(); +PCC_NORETURN void ShowHelp(); + +} // namespace pcc + +#endif diff --git a/getopt.c b/getopt.c new file mode 100644 index 0000000..b5eebdf --- /dev/null +++ b/getopt.c @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2012-2017, Kim Grasman <kim.grasman@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Kim Grasman nor the + * names of contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRASMAN BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +#include "getopt.h" + +#include <stddef.h> +#include <string.h> + +char* optarg; +int optopt; +/* The variable optind [...] shall be initialized to 1 by the system. */ +int optind = 1; +int opterr; + +static char* optcursor = NULL; + +/* Implemented based on [1] and [2] for optional arguments. + optopt is handled FreeBSD-style, per [3]. + Other GNU and FreeBSD extensions are purely accidental. + +[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html +[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +[3] +http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE +*/ +int getopt(int argc, char* const argv[], const char* optstring) { + int optchar = -1; + const char* optdecl = NULL; + + optarg = NULL; + opterr = 0; + optopt = 0; + + /* Unspecified, but we need it to avoid overrunning the argv bounds. */ + if (optind >= argc) goto no_more_optchars; + + /* If, when getopt() is called argv[optind] is a null pointer, getopt() + shall return -1 without changing optind. */ + if (argv[optind] == NULL) goto no_more_optchars; + + /* If, when getopt() is called *argv[optind] is not the character '-', + getopt() shall return -1 without changing optind. */ + if (*argv[optind] != '-') goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "-", + getopt() shall return -1 without changing optind. */ + if (strcmp(argv[optind], "-") == 0) goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "--", + getopt() shall return -1 after incrementing optind. */ + if (strcmp(argv[optind], "--") == 0) { + ++optind; + goto no_more_optchars; + } + + if (optcursor == NULL || *optcursor == '\0') optcursor = argv[optind] + 1; + + optchar = *optcursor; + + /* FreeBSD: The variable optopt saves the last known option character + returned by getopt(). */ + optopt = optchar; + + /* The getopt() function shall return the next option character (if one is + found) from argv that matches a character in optstring, if there is + one that matches. */ + optdecl = strchr(optstring, optchar); + if (optdecl) { + /* [I]f a character is followed by a colon, the option takes an + argument. */ + if (optdecl[1] == ':') { + optarg = ++optcursor; + if (*optarg == '\0') { + /* GNU extension: Two colons mean an option takes an + optional arg; if there is text in the current argv-element + (i.e., in the same word as the option name itself, for + example, + "-oarg"), then it is returned in optarg, otherwise optarg is + set to zero. */ + if (optdecl[2] != ':') { + /* If the option was the last character in the string + pointed to by an element of argv, then optarg shall + contain the next element of argv, and optind shall be + incremented by 2. If the resulting value of optind is + greater than argc, this indicates a missing + option-argument, and getopt() shall return an error + indication. + + Otherwise, optarg shall point to the string following the + option character in that element of argv, and optind + shall be incremented by 1. + */ + if (++optind < argc) { + optarg = argv[optind]; + } else { + /* If it detects a missing option-argument, it shall + return the colon character ( ':' ) if the first + character of optstring was a colon, or a + question-mark character ( '?' ) otherwise. + */ + optarg = NULL; + optchar = (optstring[0] == ':') ? ':' : '?'; + } + } else { + optarg = NULL; + } + } + + optcursor = NULL; + } + } else { + /* If getopt() encounters an option character that is not contained in + optstring, it shall return the question-mark ( '?' ) character. */ + optchar = '?'; + } + + if (optcursor == NULL || *++optcursor == '\0') ++optind; + + return optchar; + +no_more_optchars: + optcursor = NULL; + return -1; +} + +/* Implementation based on [1]. + +[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +*/ +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex) { + const struct option* o = longopts; + const struct option* match = NULL; + int num_matches = 0; + size_t argument_name_length = 0; + const char* current_argument = NULL; + int retval = -1; + + optarg = NULL; + optopt = 0; + + if (optind >= argc) return -1; + + if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) + return getopt(argc, argv, optstring); + + /* It's an option; starts with -- and is longer than two chars. */ + current_argument = argv[optind] + 2; + argument_name_length = strcspn(current_argument, "="); + for (; o->name; ++o) { + if (strncmp(o->name, current_argument, argument_name_length) == 0) { + match = o; + ++num_matches; + } + } + + if (num_matches == 1) { + /* If longindex is not NULL, it points to a variable which is set to the + index of the long option relative to longopts. */ + if (longindex) *longindex = (match - longopts); + + /* If flag is NULL, then getopt_long() shall return val. + Otherwise, getopt_long() returns 0, and flag shall point to a + variable which shall be set to val if the option is found, but left + unchanged if the option is not found. */ + if (match->flag) *(match->flag) = match->val; + + retval = match->flag ? 0 : match->val; + + if (match->has_arg != no_argument) { + optarg = strchr(argv[optind], '='); + if (optarg != NULL) ++optarg; + + if (match->has_arg == required_argument) { + /* Only scan the next argv for required arguments. Behavior is + not + specified, but has been observed with Ubuntu and Mac OSX. */ + if (optarg == NULL && ++optind < argc) { + optarg = argv[optind]; + } + + if (optarg == NULL) retval = ':'; + } + } else if (strchr(argv[optind], '=')) { + /* An argument was provided to a non-argument option. + I haven't seen this specified explicitly, but both GNU and + BSD-based implementations show this behavior. + */ + retval = '?'; + } + } else { + /* Unknown option or ambiguous match. */ + retval = '?'; + } + + ++optind; + return retval; +} diff --git a/getopt.h b/getopt.h new file mode 100644 index 0000000..03f769f --- /dev/null +++ b/getopt.h @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2012-2017, Kim Grasman <kim.grasman@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Kim Grasman nor the + * names of contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRASMAN BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +#ifndef INCLUDED_GETOPT_PORT_H +#define INCLUDED_GETOPT_PORT_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#define no_argument 1 +#define required_argument 2 +#define optional_argument 3 + +extern char* optarg; +extern int optind, opterr, optopt; + +struct option { + const char* name; + int has_arg; + int* flag; + int val; +}; + +int getopt(int argc, char* const argv[], const char* optstring); + +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex); + +#if defined(__cplusplus) +} +#endif + +#endif // INCLUDED_GETOPT_PORT_H @@ -0,0 +1,40 @@ +#include <iostream> + +#ifdef _MSC_VER +#include "getopt.h" +#else +#include <unistd.h> +#endif + +#include "Driver.hh" +#include "Log.hh" +#include "Version.hh" + +int main(int argc, char* argv[]) { + int rv; + pcc::LogLevel level = pcc::PCC_WARNING; + while ((rv = getopt(argc, argv, "vVh")) != -1) { + switch (rv) { + case 'v': + level = pcc::PCC_DEBUG; + break; + case 'V': + pcc::ShowVersion(); + case 'h': + pcc::ShowHelp(); + default: + pcc::Log(pcc::PCC_ERROR, "Unknown option \"%c\".", rv); + pcc::ShowHelp(); + } + } + if (optind >= argc) { + pcc::Log(pcc::PCC_ERROR, "No input file specified"); + return 0; + } + for (int i = optind; i < argc; i++) { + pcc::Context context(argv[i]); + pcc::Driver driver(&context); + driver.Parse(argv[i]); + } + return 0; +} diff --git a/node/BaseNode.cc b/node/BaseNode.cc new file mode 100644 index 0000000..98ebb82 --- /dev/null +++ b/node/BaseNode.cc @@ -0,0 +1,6 @@ +#include "BaseNode.hh" + +namespace pcc { +BaseNode::BaseNode(Driver* driver) + : driver_(driver) {} +} // namespace pcc diff --git a/node/BaseNode.hh b/node/BaseNode.hh new file mode 100644 index 0000000..ae0ccea --- /dev/null +++ b/node/BaseNode.hh @@ -0,0 +1,21 @@ +#ifndef PCC_BASE_H +#define PCC_BASE_H + +#include <llvm/IR/Value.h> + +#include "Driver.hh" + +namespace pcc { +using Value = llvm::Value*; + +class BaseNode { + public: + virtual Value CodeGen() = 0; + BaseNode(Driver* driver); + + protected: + Driver* driver_; +}; +} // namespace pcc + +#endif diff --git a/node/LiteralNode.cc b/node/LiteralNode.cc new file mode 100644 index 0000000..57cc65b --- /dev/null +++ b/node/LiteralNode.cc @@ -0,0 +1,22 @@ +#include "LiteralNode.hh" + +namespace pcc { +StringLiteralNode::StringLiteralNode(Driver* driver, char* value) + : BaseNode(driver) + , value_(value) {} + +Value StringLiteralNode::CodeGen() { + llvm::Module* module = driver_->GetModule(); + llvm::LLVMContext& context = module->getContext(); + llvm::Constant* str = llvm::ConstantDataArray::getString(context, value_); + llvm::Type* type = str->getType(); + llvm::GlobalVariable* var = new llvm::GlobalVariable( + *module, type, true, llvm::GlobalVariable::InternalLinkage, str); + llvm::Constant* zero = + llvm::Constant::getNullValue(llvm::IntegerType::getInt32Ty(context)); + llvm::Constant* indices[] = {zero, zero}; + llvm::Constant* ptr = + llvm::ConstantExpr::getGetElementPtr(type, var, indices, true); + return ptr; +} +} // namespace pcc diff --git a/node/LiteralNode.hh b/node/LiteralNode.hh new file mode 100644 index 0000000..2e9b43a --- /dev/null +++ b/node/LiteralNode.hh @@ -0,0 +1,17 @@ +#ifndef PCC_LITERALNODE_H +#define PCC_LITERALNODE_H + +#include "BaseNode.hh" + +namespace pcc { +class StringLiteralNode : public BaseNode { + public: + StringLiteralNode(Driver* driver, char* value); + Value CodeGen() override; + + private: + char* value_; +}; +} // namespace pcc + +#endif @@ -0,0 +1,17 @@ +program a; +VAR + f : integer; + g : real; + h : boolean; + j : integer; + +function test(a:integer;b:string):char; +var s1:real; +begin + f:=b; + g:=c; + if g<=c then + h:=ture + else + h:=false; +end; |
