├── .gitignore ├── LICENSE ├── README.md ├── TODO ├── include └── classp.h ├── src ├── Makefile ├── TODO ├── classp.cc ├── classp.l ├── classp.y ├── cpp11-generator.cc ├── formatter-generator.cc ├── lexer-base.cc ├── lexer-base.h ├── parse-tree.cc ├── parse-tree.h ├── parser-base.cc ├── parser-base.h ├── parser-generator.cc ├── skeleton.h ├── skeleton.l ├── skeleton.sed ├── skeleton.y ├── stringprintf.cc ├── stringprintf.h ├── stub-main.cc └── test.sh └── tests ├── alt1 ├── assign1 ├── assign1.h ├── assign1.l ├── assign1.y ├── calculator1 ├── calculator1.h ├── calculator1.l ├── calculator1.y ├── classp_lang ├── classp_lang.h ├── classp_lang.l ├── classp_lang.y ├── example.y ├── example1 ├── example1.h ├── example1.l ├── example1.y ├── example2 ├── example2.h ├── example2.l ├── example2.y ├── expr1 ├── expr1.h ├── expr1.l ├── expr1.y ├── prec1 ├── prec1.h ├── prec1.l ├── prec1.y ├── prec2 ├── prec2.h ├── prec2.l ├── prec2.y ├── prec3 ├── prec4 ├── prec4.h ├── prec4.l ├── prec4.y ├── samples ├── samples.h ├── samples.l ├── samples.out ├── samples.y ├── sql1 ├── t1 ├── t1.h ├── t1.l ├── t1.y ├── t10 ├── t10.h ├── t10.l ├── t10.y ├── t11 ├── t11.h ├── t11.l ├── t11.y ├── t2 ├── t2.h ├── t2.l ├── t2.y ├── t3 ├── t3.h ├── t3.l ├── t3.y ├── t4 ├── t4.h ├── t4.l ├── t4.y ├── t5 ├── t5.h ├── t5.l ├── t5.y ├── t6 ├── t6.h ├── t6.l ├── t6.y ├── t7 ├── t7.h ├── t7.l ├── t7.y ├── t8 ├── t8.h ├── t8.l ├── t8.y ├── t9 ├── t9.h ├── t9.l └── t9.y /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Generated files 31 | *.yacc.* 32 | *.lex.* 33 | *.d 34 | location.hh 35 | position.hh 36 | stack.hh 37 | src/classp 38 | src/skeleton-generator.h 39 | 40 | tmp/ 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This directory contains an implementation of Classp written by David Gudeman 2 | (dgudeman@google.com or dave.gudeman@gmail.com). 3 | 4 | #INTRODUCTION 5 | The Classp language is a system for writing parsers without writing a grammar. 6 | Grammars are designed to describe the surface structure of a language rather 7 | than the logical structure that the programmer really wants to work with. 8 | Grammars also make use of concepts that are not easily compatible with normal 9 | programming languages, making them an awkward fit for parsing. 10 | 11 | Classp takes a radically different approach; it starts with the abstract 12 | syntax tree (AST) which represents the logical structure of the language. 13 | These ASTs are defined with classes and with inheritance, just as you would 14 | normally define an AST in a modern object-oriented language. Each class 15 | has a class pattern (hence, CLASSPattern) which says what that class looks 16 | like in language form. Classp turns these class patterns into a parser and 17 | formatter for the AST. 18 | 19 | A Classp AST description is compiled by classp into C++, Bison, and Flex. 20 | The language is documented in the [language manual](https://docs.google.com/document/d/1hqtbPkKbA5janVVb0xEXg4n1nGKs3tCgijK2PFRCx2k/edit?usp=sharing). 21 | The program itself is documented in the [user manual](https://docs.google.com/document/d/1Qq3R87a-_Aru8DXXVpxM35y5rWWwrJ1tpKoWs3y0o1U/edit?usp=sharing). 22 | 23 | #BUILDING AND TESTING 24 | The source code is in the src subdirectory. It runs on Linux and builds with Bison 3.02 25 | or later, Flex 2.5.39 or later, and g++ 4.8.2. 26 | 27 | Cd to the src directory and type 28 | 29 | ```shell 30 | make classp 31 | ``` 32 | 33 | This will create all intermediate and object files as well as the executable, 34 | classp, in the srce directory. To run tests of the code generation type 35 | 36 | ```shell 37 | make tests 38 | ```` 39 | 40 | To have some tests actually run and execute sample parses type 41 | 42 | ```shell 43 | make samples 44 | ``` 45 | 46 | #CLASSP FOR THE IMPATIENT 47 | After building Classp as described above, here is a quick example of using it. Suppose 48 | the main directory is DIR, then enter the following lines in the shell: 49 | ``` 50 | export CLASSP_TOP_DIR=DIR 51 | alias classp=$CLASSP_TOP_DIR/src/classp 52 | export CLASSP_INCLUDE=$CLASSP_TOP_DIR/include 53 | ``` 54 | Create a classp file: 55 | ``` 56 | cat >test.classp <main.cc < 102 | int main(int, char**) { 103 | test::AstNode* expr = test::Expression::parse(std::cin, std::cout); 104 | if (expr) { expr->format(std::cout); std::cout << "\n"; } 105 | else std::cout << "parse failed\n"; 106 | return 0; 107 | } 108 | EOF 109 | ``` 110 | Build it 111 | ``` 112 | g++ -std=c++11 -I$CLASSP_INCLUDE main.cc test.a 113 | ``` 114 | Run the program 115 | ``` 116 | ./a.out < * ). Generalize 39 | to ( * ) where matches any pattern that does not 40 | have an attribute. Also allow ( * ) where is an 41 | alternation. For example: ((extern_flag | static_flag | register_flag)*) to 42 | parse a sequence of flags. 43 | 44 | * DONE (dgudeman) Implement assignment patterns: 45 | '{' ( '->' *|) '}' 46 | 47 | * We need to deal with passing a string as the value of a production. We could 48 | either pass pointers to string and deal with allocation, or we could define our 49 | own data types to enable it. 50 | 51 | * Make it work with only standard tools (not dependent on google3). 52 | 53 | * Get the output compiling and executing. Produce a simple API for the user. 54 | See ParserBase::directory. 55 | 56 | * Seperate class defs into .h and .cc files. 57 | 58 | * DONE (dgudeman) Get inheritance working: 59 | class A { 60 | int x; 61 | syntax('(' $0 ')'); // parentheses syntax 62 | } 63 | class B extends A { 64 | int y; 65 | syntax( 'first' x ', second' y ); 66 | } 67 | 1. DONE Every class needs to know what its child classes are. 68 | 2. DONE The rule for a class A with children is an alternation of the syntax for A 69 | and the nonterminals for all of its children. The actual class type produced 70 | is usually a child type such as B rather than A. 71 | 3. DONE Generalize this alternation 72 | concept so that a single class can have multiple 73 | class syntaxes and they become alternations. 74 | 4. DONE A '$$' in a class syntax causes a recursive match of the class, but does not 75 | create a new object. For example, if you match the parentheses syntax for A 76 | then it recursively matches A, but only one A object is created. 77 | 78 | * Right now it is an unchecked error to have more than one regular (that is, 79 | not '$$') syntaxes for a class. 80 | 81 | * DONE Precedence and associativity(dgudeman) 82 | These are associated with rules, not symbols, so they have to be implemented by 83 | structuring the grammar rules insead of using directives like %left. For example 84 | class Operation extends Expression { 85 | class Expression args[]; 86 | } 87 | class Addition extends Operation { 88 | syntax (args[1] '+' args[2], left 6); 89 | } 90 | class Multiplication extends Operation { 91 | syntax (args[1] '*' args[2], left 4); 92 | } 93 | 94 | ** FEATURES AND PERFORMANCE 95 | 96 | * Multiple syntaxes. Write a syntax for language A and one for language B, and 97 | you automatically get an A->B translator and a B->A translator. For example: 98 | class A { 99 | syntax sql("...") c("..."); 100 | } 101 | Multiple syntaxes may also be needed for a single language. Suppose there is a 102 | class C that is parsed entirely differently in two different contexts A and B, 103 | but it still makes sense to make it a single class in the AST. Then we can do it 104 | like this: 105 | class C { 106 | ... 107 | syntax A_context {...} 108 | syntax B_context {...} 109 | } 110 | class A { 111 | ... 112 | C c 113 | syntax(... A_context:c ...) 114 | } 115 | class B { 116 | ... 117 | C c 118 | syntax(... B_context:c ...) 119 | } 120 | 121 | * Cut operator: ( ! ). If ends in an iterator (+ or *) 122 | then it is normally greedy, but this will cut it off before any expression that 123 | matches . 124 | 125 | * Cooperation operator: ( & ). Matches only if it both 126 | and match. 127 | 128 | * Output for other parser generators and languages. The parser generator has to 129 | handle left recursion so not JavaCC. I also don't know if we are going to need 130 | other features that can't be parsed by LR or LL parsers so it would be best to 131 | look into general parsers (GLR, GLL, Earley, etc.) like Elkhound. Note that 132 | bison has a GLR mode if we need it. 133 | 134 | * Generate our own GLL parser and eliminate the requirement for a separate 135 | parser generator. 136 | 137 | * Expand double-quotes into parse expressions. Eg: 138 | class Addition { 139 | Expression args[]; 140 | syntax("$1 + $2"); // equivalent to syntax ( args[1] '+' args[2]) 141 | } 142 | 143 | * Implement syntax elements attached to attributes. The semantics are as follows 144 | class A { 145 | int x syntax(... $0 ...); // attribute syntax for x 146 | syntax(... x ...); // class syntax 147 | } 148 | When you see x in the class syntax or in any other attribute syntax, then it is 149 | replaced by the attribute syntax for x. The $0 in the attribute syntax for x is 150 | replaced by a parser for x. 151 | 152 | * Extend array syntax so that you can parse 153 | syntax('prefix' array 'suffix'*'separator); 154 | 155 | * If there are two more places where an array of T is parsed with the same 156 | prefix, suffix, and separator, then only generate one production for all of 157 | them. 158 | 159 | ** DOCUMENTATION 160 | 161 | * internal web site 162 | 163 | * user manual 164 | 165 | ** SELF PARSING 166 | We should get to a self-parsing situation as soon as possible so we don't have 167 | to maintain the bison code. Still needed: 168 | 169 | * precedence and associativity 170 | 171 | * enums 172 | 173 | * An alternation that includes array attributes. The array attribute may appear 174 | multiple times, adding to the appropriate array. 175 | -------------------------------------------------------------------------------- /include/classp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Classp parser, formatter, and AST generator. 3 | * Description: These structs are used for both the parse tree and AST. 4 | * 5 | * Copyright 2015 Google Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | */ 20 | #ifndef CLASSP_H_ 21 | #define CLASSP_H_ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace classp { 31 | 32 | // Common Base class for all AST nodes. Each classp file also generates its own 33 | // base class that inherits from ClasspNode. 34 | class ClasspNode { 35 | public: 36 | 37 | // Returns the name of this class. 38 | virtual std::string className() { return "ClasspNode"; } 39 | 40 | virtual ~ClasspNode() {} 41 | 42 | // Writes out a human-readable tree structure of the AST. 43 | void print(std::ostream& out) { 44 | out << "(" << className(); 45 | printMembers(out); 46 | out << ")"; 47 | } 48 | 49 | // Prints the members of this node for print(). 50 | virtual void printMembers(std::ostream& out) {} 51 | 52 | // Writes the AST in the declared syntax. 53 | virtual void format(std::ostream& out, int precedence) = 0; 54 | 55 | // Writes the AST in the declared syntax starting with no precedence. 56 | virtual void format(std::ostream& out) { 57 | format(out, 0); 58 | } 59 | }; 60 | 61 | // Helper functions for ClasspNode::print() and ClasspNode::format() that can handle 62 | // null trees and leaf values that are not ClasspNodes. 63 | template void classpPrint(std::ostream& out, T val) { 64 | out << std::boolalpha << val; 65 | } 66 | template void classpPrint(std::ostream& out, std::vector arr) { 67 | const char* separator = ""; 68 | out << "["; 69 | for (const auto& val : arr) { 70 | out << separator; 71 | classpPrint(out, val); 72 | separator = ", "; 73 | } 74 | out << "]"; 75 | } 76 | template void classpPrint(std::ostream& out, T* val) { 77 | if (val) val->print(out); 78 | else out << "nullptr"; 79 | } 80 | 81 | template void classpFormat(std::ostream& out, int precedence, T val) { 82 | out << std::boolalpha << val; 83 | } 84 | template void classpFormat(std::ostream& out, int precedence, T* val) { 85 | if (val) val->format(out, precedence); 86 | else out << "***MISSING***"; // this is an error case 87 | } 88 | 89 | // RestrictedUnion is a restricted variant class that must be read exactly 90 | // once and can't be copied, only moved. That is, the object must 91 | // not be destroyed until it has either been copied (with the copy constructor) 92 | // or the value has been extracted with Take(). 93 | class RestrictedUnion { 94 | public: 95 | template RestrictedUnion(const T& value) { 96 | data = (void*)new T(value); 97 | } 98 | 99 | // The copy constructor moves the value 100 | RestrictedUnion(const RestrictedUnion& old) { 101 | data = old.data; 102 | old.data = nullptr; 103 | } 104 | 105 | ~RestrictedUnion() { 106 | assert(!data); 107 | } 108 | 109 | // Return the attribute value. 110 | template T& Ref() { 111 | assert(data); 112 | return *(T*)data; 113 | } 114 | 115 | // Get the attribute value while destroying the copy in the variant. 116 | template void Take(T& value) { 117 | assert(data); 118 | value = *(T*)data; 119 | delete (T*)data; 120 | data = nullptr; 121 | } 122 | 123 | RestrictedUnion& operator=(RestrictedUnion&) = delete; 124 | 125 | mutable void* data; 126 | }; 127 | 128 | // AttributeMap implements a mapping from attribute names to values-> It is 129 | // used to simulate keyword parameters in the constructors for the ClasspNode 130 | // classes and also to build up the set of keyword parameters during parsing. 131 | class AttributeMap { 132 | public: 133 | AttributeMap() { 134 | values = new std::map(); 135 | } 136 | // Add all of the elements of map2 into this, deleting map2 137 | void Merge(AttributeMap& map2) { 138 | for (auto iter = map2.values->begin(); iter != map2.values->end(); iter++) { 139 | values->emplace(iter->first, iter->second); 140 | } 141 | // Because the RestrictedUnion objects were copied out of map2 using the 142 | // destructive copy operator, they are now all blank. 143 | delete map2.values; 144 | map2.values = nullptr; 145 | } 146 | 147 | // Push value onto the array attribute, creating a new array if needed. 148 | template void Push(const std::string& attribute, T value) { 149 | auto iterator = values->find(attribute); 150 | if (values->count(attribute) == 0) { 151 | iterator = values->emplace(attribute, std::vector()).first; 152 | } 153 | iterator->second.Ref< std::vector >().push_back(value); 154 | } 155 | 156 | // Set the attribute to value. It is an error if attribute is already set. 157 | template void Add(const std::string& attribute, T value) { 158 | values->emplace(attribute, value); 159 | } 160 | 161 | template bool Take(const std::string& attribute, T& value) { 162 | if (!values) return false; 163 | auto iter = values->find(attribute); 164 | if (iter == values->end()) { 165 | if (values->empty()) { 166 | // this catches the case where nothing was ever put into values. 167 | delete values; 168 | values = nullptr; 169 | } 170 | return false; 171 | } 172 | iter->second.Take(value); 173 | values->erase(iter); 174 | if (values->empty()) { 175 | delete values; 176 | values = nullptr; 177 | } 178 | return true; 179 | } 180 | 181 | void AssertEmpty() { 182 | assert(values == nullptr); 183 | } 184 | 185 | std::map* values; 186 | }; 187 | 188 | } // namespace classp 189 | 190 | #endif // CLASSP_H_ 191 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | OFILES=formatter-generator.o lexer-base.o parse-tree.o cpp11-generator.o \ 2 | parser-generator.o parser-base.o stringprintf.o classp.o \ 3 | classp.yacc.o classp.lex.o 4 | CCFILES=${OFILES:.o=.cc} 5 | YHEADERS=classp.yacc.hh location.hh stack.hh position.hh 6 | GENERATE_TESTS=t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 \ 7 | prec1 prec2 prec4 assign1 example1 example2 classp_lang expr1 \ 8 | calculator1 9 | SAMPLES_TESTS=samples t1 t2 t3 t4 t5 t11 \ 10 | assign1 example1 example2 expr1 prec2 prec4 11 | SKELETON_FILES=skeleton.h skeleton.y skeleton.l 12 | TEST_SOURCE=../tests 13 | TEST_TMP=/tmp/classp-test 14 | 15 | c=-g 16 | CXXFLAGS:=$(c) -std=c++11 -Wall -Wno-sign-compare 17 | LEX=/usr/bin/flex 18 | YACC=/usr/bin/bison 19 | # This is for calling classp, not building it 20 | CLASSP=./classp 21 | INSTALL_DIR=../bin 22 | 23 | %.o: %.cc 24 | $(CXX) -c $(CXXFLAGS) $*.cc -o $*.o 25 | $(CXX) -MM $(CXXFLAGS) $*.cc > $*.d 26 | 27 | classp: $(OFILES) 28 | $(CXX) -o $@ $(OFILES) 29 | 30 | classp.lex.cc: classp.l 31 | $(LEX) -o $@ classp.l 32 | 33 | classp.yacc.cc $(YHEADERS): classp.y 34 | $(YACC) -o classp.yacc.cc classp.y 35 | 36 | parser-base.o : skeleton-generator.h 37 | 38 | skeleton-generator.h : skeleton.sed $(SKELETON_FILES) 39 | sed -f skeleton.sed $(SKELETON_FILES) >$@ 40 | 41 | # 42 | # Testing 43 | # 44 | tests: classp 45 | ./test.sh $(GENERATE_TESTS) -rc samples 46 | 47 | samples: classp 48 | ./test.sh -r $(SAMPLES_TESTS) 49 | 50 | update-all-generate-tests: tests 51 | ./test.sh -U $(GENERATE_TESTS) samples 52 | 53 | clean-t1: classp 54 | mkdir -p $(TEST_TMP) 55 | rm -f $(TEST_TMP)/* 56 | cp stub-main.cc $(TEST_SOURCE)/t1 $(TEST_TMP) 57 | 58 | test-libs: clean-t1 59 | ./classp -La $(TEST_TMP)/t1 60 | (cd $(TEST_TMP) ; g++ -std=c++11 -I$$CLASSP_INCLUDE -Wall stub-main.cc t1.a && ./a.out) 61 | ./classp -Ld $(TEST_TMP)/t1 62 | (cd $(TEST_TMP) ; g++ -std=c++11 -I$$CLASSP_INCLUDE -Wall -L$(TEST_TMP) stub-main.cc -lt1 && LD_LIBRARY_PATH=$(TEST_TMP) ./a.out) 63 | 64 | all-tests: tests samples test-libs 65 | # 66 | # Installation and cleaning 67 | # 68 | install: $(INSTALL_DIR)/classp 69 | 70 | $(INSTALL_DIR)/classp: classp 71 | cp classp $(INSTALL_DIR) 72 | 73 | clean: 74 | rm -f classp $(OFILES) classp.lex.cc classp.yacc.cc $(YHEADERS) *.d \ 75 | skeleton-generator.h 76 | 77 | .PHONY: install clean tests samples update-all-generate-tests \ 78 | clean-t1 test-libs all-tests 79 | 80 | # Dependency management 81 | $(OFILES) : $(YHEADERS) 82 | 83 | # pull in dependency info for existing .o files 84 | -include $(OFILES:.o=.d) 85 | -------------------------------------------------------------------------------- /src/TODO: -------------------------------------------------------------------------------- 1 | ** BASIC USEABILITY 2 | 3 | Bug in tests/alt1 4 | 5 | * DONE (dgudeman) Parsing problem: 6 | class A { 7 | int a[]; 8 | syntax('!' a*); 9 | } 10 | We want something like 11 | A : {...} 12 | | '!' TOK_INTEGER {...} 13 | | A '!' TOK_INTEGER {...} 14 | 15 | * Write tests for error cases, and improve error messages. 16 | 17 | * More comprehensive test for non-error cases. 18 | 19 | * DONE (dgudeman) Get alternation working 20 | 21 | * DONE Currently there is no storage management of the parse tree. Add ownership of 22 | pointers and freeing them when possible. 23 | 24 | * Get namespaces working. See ParserBase::namespace_tag. 25 | 26 | * Figure out the story for lexical rules. How can you specify things like 27 | whitespace definition and case-insensitivity in one place to apply to all rules? 28 | How do you then write lexical rules that ignore these specifications? See 29 | (http://tutor.rascal-mpl.org/Rascal/Concepts/Concepts.html) for another sytem 30 | that does this. 31 | 32 | * ???Inheritance matching: name an inherited type instead of an attribute and it 33 | expands the inherited syntax in place. ??? Find useful examples first. I'm no 34 | longer sure that multiple inheritance of syntax is a good idea. 35 | 36 | * DONE (dgudeman) Array matching is currently restricted to 37 | ( * ). Generalize 38 | to ( * ) where matches any pattern that does not 39 | have an attribute. Also allow ( * ) where is an 40 | alternation. For example: ((extern_flag | static_flag | register_flag)*) to 41 | parse a sequence of flags. 42 | 43 | * DONE (dgudeman) Implement assignment patterns: 44 | '{' ( '->' *|) '}' 45 | 46 | * DONE We need to deal with passing a string as the value of a production. We could 47 | either pass pointers to string and deal with allocation, or we could define our 48 | own data types to enable it. 49 | 50 | * DONE (dgudeman) Make it work with only standard tools (not dependent on 51 | google3). 52 | 53 | * DONE Get the output compiling and executing. Produce a simple API for the user. 54 | See ParserBase::directory. 55 | 56 | * DONE Seperate class defs into .h and .cc files. 57 | 58 | * DONE (dgudeman) Get inheritance working: 59 | class A { 60 | int x; 61 | syntax('(' $0 ')'); // parentheses syntax 62 | } 63 | class B extends A { 64 | int y; 65 | syntax( 'first' x ', second' y ); 66 | } 67 | 1. DONE Every class needs to know what its child classes are. 68 | 2. DONE The rule for a class A with children is an alternation of the syntax for A 69 | and the nonterminals for all of its children. The actual class type produced 70 | is usually a child type such as B rather than A. 71 | 3. DONE Generalize this alternation 72 | concept so that a single class can have multiple 73 | class syntaxes and they become alternations. 74 | 4. DONE A '$$' in a class syntax causes a recursive match of the class, but does not 75 | create a new object. For example, if you match the parentheses syntax for A 76 | then it recursively matches A, but only one A object is created. 77 | 78 | * Right now it is an unchecked error to have more than one regular (that is, 79 | not '$$') syntaxes for a class. 80 | 81 | * DONE Precedence and associativity(dgudeman) 82 | These are associated with rules, not symbols, so they have to be implemented by 83 | structuring the grammar rules insead of using directives like %left. For example 84 | class Operation extends Expression { 85 | class Expression args[]; 86 | } 87 | class Addition extends Operation { 88 | syntax (args[1] '+' args[2], left 6); 89 | } 90 | class Multiplication extends Operation { 91 | syntax (args[1] '*' args[2], left 4); 92 | } 93 | 94 | ** FEATURES AND PERFORMANCE 95 | 96 | * Add an enum for class types, and isa functions for each class. 97 | 98 | * Multiple syntaxes. Write a syntax for language A and one for language B, and 99 | you automatically get an A->B translator and a B->A translator. For example: 100 | class A { 101 | syntax sql("...") c("..."); 102 | } 103 | Multiple syntaxes may also be needed for a single language. Suppose there is a 104 | class C that is parsed entirely differently in two different contexts A and B, 105 | but it still makes sense to make it a single class in the AST. Then we can do it 106 | like this: 107 | class C { 108 | ... 109 | syntax A_context {...} 110 | syntax B_context {...} 111 | } 112 | class A { 113 | ... 114 | C c 115 | syntax(... A_context:c ...) 116 | } 117 | class B { 118 | ... 119 | C c 120 | syntax(... B_context:c ...) 121 | } 122 | 123 | * Attribute evaluation. 124 | 125 | * Cut operator: ( ! ). If ends in an iterator (+ or *) 126 | then it is normally greedy, but this will cut it off before any expression that 127 | matches . 128 | 129 | * Cooperation operator: ( & ). Matches only if it both 130 | and match. 131 | 132 | * Output for other parser generators and languages. The parser generator has to 133 | handle left recursion so not JavaCC. I also don't know if we are going to need 134 | other features that can't be parsed by LR or LL parsers so it would be best to 135 | look into general parsers (GLR, GLL, Earley, etc.) like Elkhound. Note that 136 | bison has a GLR mode if we need it. 137 | 138 | * Generate our own GLL parser and eliminate the requirement for a separate 139 | parser generator. 140 | 141 | * Expand double-quotes into parse expressions. Eg: 142 | class Addition { 143 | Expression args[]; 144 | syntax("$1 + $2"); // equivalent to syntax ( args[1] '+' args[2]) 145 | } 146 | 147 | * DONE Implement syntax elements attached to attributes. The semantics are as follows 148 | class A { 149 | int x syntax(... $0 ...); // attribute syntax for x 150 | syntax(... x ...); // class syntax 151 | } 152 | When you see x in the class syntax or in any other attribute syntax, then it is 153 | replaced by the attribute syntax for x. The $0 in the attribute syntax for x is 154 | replaced by a parser for x. 155 | 156 | * DONE (dgudeman) Extend array syntax so that you can parse 157 | syntax('prefix' array 'suffix'*'separator); 158 | 159 | * If there are two more places where an array of T is parsed with the same 160 | prefix, suffix, and separator, then only generate one production for all of 161 | them. 162 | 163 | ** DOCUMENTATION 164 | 165 | * internal web site 166 | 167 | * user manual 168 | 169 | ** SELF PARSING 170 | We should get to a self-parsing situation as soon as possible so we don't have 171 | to maintain the bison code. Still needed: 172 | 173 | * DONE precedence and associativity 174 | 175 | * DONE enums 176 | 177 | * DONE An alternation that includes array attributes. The array attribute may appear 178 | multiple times, adding to the appropriate array. 179 | -------------------------------------------------------------------------------- /src/classp.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Classp parser, formatter, and AST generator. 3 | * Description: main() and some helper functions. 4 | * 5 | * Copyright 2015 Google Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | */ 20 | #include "parser-base.h" 21 | #include "lexer-base.h" 22 | 23 | #include 24 | #include 25 | using std::ofstream; 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef _WIN32 31 | #define PATH_SEPARATOR '\\' 32 | #else 33 | #define PATH_SEPARATOR '/' 34 | #endif 35 | 36 | static void SplitFileName(const string& name, string* directory, string* base, string* extension) { 37 | size_t last_separator = name.rfind(PATH_SEPARATOR); 38 | string filename; 39 | if (last_separator == string::npos) { 40 | *directory = ""; 41 | filename = name; 42 | } else { 43 | *directory = name.substr(0, last_separator+1); 44 | filename = name.substr(last_separator+1); 45 | } 46 | size_t last_dot = filename.rfind('.'); 47 | if (last_dot == string::npos) { 48 | *base = filename; 49 | *extension = ""; 50 | } else { 51 | *base = filename.substr(0, last_dot); 52 | *extension = filename.substr(last_dot); 53 | } 54 | } 55 | 56 | void usage() { 57 | std::cerr << "usage: classp -[bxs] [-L[ad]*] [-I] \n"; 58 | } 59 | 60 | int main(int argc, char** argv) { 61 | int opt; 62 | bool build_static_lib = false; 63 | bool build_dynamic_lib = false; 64 | bool build_test_exe = false; 65 | bool execute = false; 66 | bool run_samples = false; 67 | char* include_dir = nullptr; 68 | 69 | while ((opt = getopt(argc, argv, "hbxsI:L:")) > 0) { 70 | switch (opt) { 71 | case 'b': build_test_exe = true; break; 72 | case 'x': execute = true; break; 73 | case 's': run_samples = true; break; 74 | case 'I': include_dir = optarg; break; 75 | case '?': exit(1); 76 | case 'L': 77 | if (strchr(optarg, 'a')) build_static_lib = true; 78 | if (strchr(optarg, 'd')) build_dynamic_lib = true; 79 | break; 80 | case 'h': usage(); exit(1); 81 | } 82 | } 83 | if (run_samples) execute = true; 84 | if (execute) build_test_exe = true; 85 | bool building = build_static_lib || build_dynamic_lib || build_test_exe; 86 | if (building && !include_dir) { 87 | include_dir = getenv("CLASSP_INCLUDE"); 88 | if (!include_dir) { 89 | std::cerr << "must specify an include dir when building\n"; 90 | exit(1); 91 | } 92 | } 93 | if (optind != argc - 1) { 94 | usage(); 95 | exit(1); 96 | } 97 | 98 | string directory; 99 | string base; 100 | string extension; 101 | char* filename = argv[optind]; 102 | SplitFileName(filename, &directory, &base, &extension); 103 | string base_pathname = directory + base; 104 | 105 | if (extension.size() > 0 && extension != ".classp") { 106 | std::cerr << "The only extension allowed is .classp\n"; 107 | exit(1); 108 | } 109 | 110 | FILE* fp = fopen(filename, "r"); 111 | if (!fp) { 112 | // maybe the open failed because we have to add the .classp extension 113 | if (base_pathname == filename) { 114 | string classp_name = base_pathname + ".classp"; 115 | fp = fopen(classp_name.c_str(), "r"); 116 | } 117 | if (!fp) { 118 | std::cerr << "can't open " << filename << "\n"; 119 | exit(1); 120 | } 121 | } 122 | 123 | classp::ParserBase parser(fp); 124 | classp::ParseTree* result = parser.Parse(); 125 | fclose(fp); 126 | if (result) { 127 | ofstream yfile(base_pathname + ".y"); 128 | ofstream hfile(base_pathname + ".h"); 129 | ofstream lfile(base_pathname + ".l"); 130 | parser.SetNamespace(base); 131 | parser.PrintParser(yfile); 132 | parser.PrintHFile(hfile); 133 | parser.PrintLexer(lfile); 134 | } else { 135 | std::cerr << "parse failed\n"; 136 | exit(1); 137 | } 138 | if (building) { 139 | const int kBufSize = 1024; 140 | char buf[kBufSize]; 141 | const char* base_name = base_pathname.c_str(); 142 | 143 | snprintf(buf, kBufSize, "bison -o %s.yacc.cc %s.y", base_name, base_name); 144 | std::cerr << "executing: " << buf << "\n"; 145 | if (system(buf)) exit(1); 146 | 147 | snprintf(buf, kBufSize, "flex -o %s.lex.cc %s.l", base_name, base_name); 148 | std::cerr << "executing: " << buf << "\n"; 149 | if (system(buf)) exit(1); 150 | 151 | if (build_test_exe) { 152 | snprintf(buf, kBufSize, "g++ -g -o %s.exe -std=c++11 -I%s -Wall -DPARSER_TEST %s.yacc.cc %s.lex.cc", 153 | base_name, include_dir, base_name, base_name); 154 | std::cerr << "executing: " << buf << "\n"; 155 | if (system(buf)) exit(1); 156 | 157 | if (!execute) exit(0); 158 | const char* local_path = ""; 159 | if (base_pathname.find(PATH_SEPARATOR) == string::npos) local_path = "./"; 160 | snprintf(buf, kBufSize, "%s%s.exe %s", local_path, base_name, run_samples ? "--samples" : ""); 161 | std::cerr << "executing: " << buf << "\n"; 162 | if (system(buf)) exit(1); 163 | } 164 | if (build_static_lib) { 165 | snprintf(buf, kBufSize, "g++ -c -std=c++11 -I%s -Wall -o %s.yacc.o %s.yacc.cc", 166 | include_dir, base_name, base_name); 167 | std::cerr << "executing: " << buf << "\n"; 168 | if (system(buf)) exit(1); 169 | snprintf(buf, kBufSize, "g++ -c -std=c++11 -I%s -Wall -o %s.lex.o %s.lex.cc", 170 | include_dir, base_name, base_name); 171 | std::cerr << "executing: " << buf << "\n"; 172 | if (system(buf)) exit(1); 173 | snprintf(buf, kBufSize, "ar rcs %s.a %s.yacc.o %s.lex.o", base_name, base_name, base_name); 174 | std::cerr << "executing: " << buf << "\n"; 175 | if (system(buf)) exit(1); 176 | } 177 | if (build_dynamic_lib) { 178 | snprintf(buf, kBufSize, "g++ -shared -fpic -o %slib%s.so -std=c++11 -I%s -Wall %s.yacc.cc %s.lex.cc", 179 | directory.c_str(), base.c_str(), include_dir, base_name, base_name); 180 | std::cerr << "executing: " << buf << "\n"; 181 | if (system(buf)) exit(1); 182 | } 183 | } 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /src/cpp11-generator.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Classp parser, formatter, and AST generator. 3 | * Description: Functions to generate the c++11 class definitions. 4 | * 5 | * Copyright 2015 Google Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | */ 20 | #include "parse-tree.h" 21 | 22 | #include "lexer-base.h" 23 | #include "parser-base.h" 24 | 25 | namespace classp { 26 | 27 | void ParseTreeClassDecl::GenerateClassDefinition(ostream& out) { 28 | out << "class " << class_name; 29 | if (parent_classes.size() > 0) { 30 | const char* separator = ": public "; 31 | for (auto elem : parent_classes) { 32 | out << separator << elem; 33 | separator = ", "; 34 | } 35 | } else { 36 | out << ": public AstNode"; 37 | } 38 | out << " {\n public:\n " 39 | << "string className() override { return \"" << class_name 40 | << "\"; }\n "; 41 | GenerateConstructorDeclaration(out); 42 | out << ";\n"; 43 | if (parseable) { 44 | out << " static " << class_name 45 | << "* parse(istream& input, ostream& errors);\n"; 46 | } 47 | GenerateClassDeclarations(out); 48 | out << "\n};\n"; 49 | } 50 | 51 | void ParseTreeClassDecl::GenerateMethodDefinitions(ostream& out) { 52 | GenerateConstructor(out); 53 | 54 | if (parseable) { 55 | out << class_name 56 | << "* " << class_name << "::parse(istream& input, ostream& errors) {\n" 57 | " return dynamic_cast<" << class_name << "*>(" << parser->namespace_tag 58 | << "::parse(input, errors));\n" 59 | "}\n"; 60 | } 61 | 62 | // Generate the printer. 63 | out << "void " << class_name << "::printMembers(ostream& out) {"; 64 | for (auto elem : parent_classes) { 65 | out << "\n " << elem << "::printMembers(out);\n"; 66 | } 67 | for (auto elem : class_body) { 68 | ParseTreeAttribute* attribute = elem->AsAttribute(); 69 | if (attribute) { 70 | attribute->GeneratePrinter(out); 71 | } 72 | } 73 | out << "\n}\n"; 74 | 75 | GenerateClassFormatter(out); 76 | } 77 | 78 | void ParseTreeAttribute::GeneratePrinter(ostream& stream) { 79 | if (is_optional && !default_value) { 80 | stream << "\n if (has_" << attribute_name << ") {" 81 | << "\n out << \" " << attribute_name << ":\";" 82 | << "\n classpPrint(out, " << attribute_name << ");" 83 | << "\n } else {" 84 | << "\n out << \"" << attribute_name << "[not defined]\";\n }"; 85 | } else { 86 | stream << "\n out << \" " << attribute_name << ":\";"; 87 | if (is_optional) { 88 | stream << "\n if (!has_" << attribute_name << ") {" 89 | << "\n out << \"[defaults to]\";"; 90 | } 91 | stream << "\n classpPrint(out, " << attribute_name << ");"; 92 | } 93 | } 94 | 95 | void ParseTreeClassDecl::GenerateClassDeclarations(ostream& out) { 96 | out << " void printMembers(ostream& out) override;\n"; 97 | 98 | GenerateClassFormatterDeclarations(out); 99 | 100 | // Generate the attribute declarations. 101 | for (auto elem : class_body) { 102 | ParseTreeAttribute* attribute = elem->AsAttribute(); 103 | if (attribute) { 104 | out << "\n " << attribute->declare_full_type << " " 105 | << attribute->attribute_name; 106 | if (attribute->is_ptr) out << " = nullptr"; 107 | out << ";"; 108 | } 109 | } 110 | 111 | // Generate the has_ declarations for optional attributes. 112 | for (auto elem : class_body) { 113 | ParseTreeAttribute* attribute = elem->AsAttribute(); 114 | if (attribute && attribute->is_optional) { 115 | out << "\n bool has_" << attribute->attribute_name << " = false;"; 116 | } 117 | } 118 | } 119 | 120 | void ParseTreeClassDecl::GenerateConstructorDeclaration(ostream& out) { 121 | out << class_name << "(" 122 | << "ParseState parseState"; 123 | for (const auto& attribute : required_params) { 124 | out << ", " << attribute->declare_full_type << " " 125 | << attribute->attribute_name; 126 | } 127 | if (has_keyword_arg) { 128 | out << ", AttributeMap& keyword_args"; 129 | } 130 | out << ")"; 131 | } 132 | 133 | void ParseTreeClassDecl::GenerateConstructor(ostream& out) { 134 | out << class_name << "::"; 135 | GenerateConstructorDeclaration(out); 136 | const char* separator = "\n : "; 137 | if (parent_classes.size() == 0) { 138 | out << separator << "AstNode(parseState)"; 139 | separator = "\n , "; 140 | } else { 141 | // Generate the parent constructors. 142 | for (auto elem : parent_classes) { 143 | out << separator << elem << "(parseState"; 144 | parser->GetClassDecl(elem)->GenerateConstructorArgs(out); 145 | out << ")"; 146 | separator = "\n , "; 147 | } 148 | } 149 | // Generate initializers for the constructor parameters. 150 | for (int i = num_inherited_required_params; i < required_params.size(); i++) { 151 | const string& name = required_params[i]->attribute_name; 152 | out << separator << name << "(" << name << ")"; 153 | separator = "\n , "; 154 | } 155 | out << " {"; 156 | if (optional_params.size() > 0) { 157 | // Generate initializers for members in the keyword list. 158 | for (const auto& attribute : optional_params) { 159 | const string& name = attribute->attribute_name; 160 | out << "\n "; 161 | if (attribute->default_value) { 162 | out << "if (!("; 163 | } 164 | if (attribute->is_optional) { 165 | out << "has_" << name << " = "; 166 | } 167 | out << "keyword_args.Take(\""<< name << "\", " << name << ")"; 168 | if (attribute->default_value) { 169 | out << ")) {\n " << name << " = "; 170 | attribute->default_value->GenerateExpression(out); 171 | out << ";\n }"; 172 | } else { 173 | out << ";"; 174 | } 175 | } 176 | } 177 | out << "\n}\n\n"; 178 | } 179 | 180 | void ParseTreeClassDecl::GenerateConstructorArgs(ostream& out) { 181 | // Generate the required params in order. 182 | for (auto attr : required_params) { 183 | out << ", " << attr->attribute_name; 184 | } 185 | if (has_keyword_arg) { 186 | out << ", keyword_args"; 187 | } 188 | } 189 | 190 | } // namespace classp 191 | -------------------------------------------------------------------------------- /src/lexer-base.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Classp parser, formatter, and AST generator. 3 | * Description: Implementation of class LexerBase. 4 | * 5 | * Copyright 2015 Google Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | */ 20 | #include "lexer-base.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "parser-base.h" 27 | 28 | namespace classp { 29 | 30 | LexerBase::LexerBase(FILE* source, ParserBase* parser) 31 | : parser_(parser), 32 | source_(source), 33 | file_name_(new string("input")), 34 | location_(file_name_.get()), 35 | initial_token_(yyParser::token::TOK_EOF) {} 36 | 37 | LexerBase::~LexerBase() { 38 | // This should be done by the parent, but it uses delete, not delete[]... 39 | delete[] yy_state_buf; 40 | yy_state_buf = NULL; 41 | 42 | if (yy_start_stack != NULL) { 43 | free(yy_start_stack); 44 | yy_start_stack = NULL; 45 | } 46 | } 47 | 48 | int LexerBase::LexerInput(char* buf, int max_size) { 49 | if (source_ == NULL) { 50 | // The file was not found. 51 | return 0; 52 | } else { 53 | int i = 0; 54 | // The following condition ensures that we can store a decoded rune. 55 | while (i < max_size) { 56 | const int c = getc(source_); 57 | if (c == EOF) { 58 | break; 59 | } else { 60 | buf[i] = c; 61 | ++i; 62 | } 63 | } 64 | return i; 65 | } 66 | } 67 | 68 | void LexerBase::LexerError(const char* msg) { 69 | parser_->Error(location_, 70 | StringPrintf("%s at %s:%d.%d-%d.%d", 71 | msg, 72 | location_.begin.filename->c_str(), 73 | location_.begin.line, 74 | location_.begin.column, 75 | location_.end.line, 76 | location_.end.column)); 77 | } 78 | 79 | const std::string* LexerBase::file_name() { 80 | return file_name_.get(); 81 | } 82 | 83 | void LexerBase::UnputAndResetLocation(char c) { 84 | assert(location_.end.column > 0); 85 | location_.end.column--; 86 | yyunput(c, yytext); 87 | } 88 | 89 | } // namespace classp 90 | -------------------------------------------------------------------------------- /src/lexer-base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Classp parser, formatter, and AST generator. 3 | * Description: Class LexerBase --the lexer that is passed to the parser. 4 | * 5 | * Copyright 2015 Google Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | */ 20 | #ifndef LEXER_BASE_H_ 21 | #define LEXER_BASE_H_ 22 | 23 | // If this is being included from classp.lex.c, then FlexLexer.h has already been 24 | // included. Otherwise, we have to include it now. This is how FlexLexer.h 25 | // says to do things 26 | #ifndef CLASSP_LEX_CC_ 27 | #include 28 | #endif 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include "classp.yacc.hh" 35 | #include "parser-base.h" 36 | 37 | class classpFlexLexer; 38 | 39 | namespace classp { 40 | 41 | class NumericValue; 42 | class ParserBase; 43 | 44 | class LexerBase : public yyFlexLexer { 45 | public: 46 | LexerBase(FILE* source, ParserBase* parser); 47 | ~LexerBase() override; 48 | 49 | // The actual lexical analyzer, whose implementation is generated by flex. 50 | virtual yyParser::symbol_type NextToken(ParserBase* parser); 51 | 52 | // The error reporting routines. 53 | void LexerError(const char* msg) override; 54 | 55 | // The name of the underlying file, if any. 56 | const std::string* file_name(); 57 | 58 | // Flex doesn't revert the location when calling unput. This function 59 | // does unput and resets the location endpoint back to what it was before. 60 | virtual void UnputAndResetLocation(char c); 61 | 62 | // Bison doesn't support multiple start states, so the recommended way to deal 63 | // with this limitation is to have an initial token that directs to parser to 64 | // look for a particular nonterminal (see the rules for start in the grammar). 65 | // This initial token is managed by these two functions: set_initial_token 66 | // is called to store the initial token in the lexer state, and 67 | // consume_initial_token is used to retrieve it. If there is no initial 68 | // token, consume_initial_token return TOK_EOF. See classp::class_plex in 69 | // parser_base.cc for details regarding the handling of the initial token. 70 | void set_initial_token(yyParser::token_type token) { initial_token_ = token; } 71 | 72 | void consume_initial_token(yyParser::token_type* token) { 73 | *token = initial_token_; 74 | initial_token_ = yyParser::token::TOK_EOF; 75 | } 76 | 77 | protected: 78 | int LexerInput(char* buf, int max_size) override; 79 | const yyParser::location_type* location() { return &location_; } 80 | 81 | private: 82 | ParserBase* const parser_; // Not owned. 83 | FILE* source_; // Not owned. 84 | std::unique_ptr file_name_; 85 | yyParser::location_type location_; 86 | yyParser::token_type initial_token_; 87 | std::stringstream current_token_; // a string token being built up 88 | 89 | // Disallow copy and assign. 90 | LexerBase(const LexerBase&) = delete; 91 | void operator=(const LexerBase&) = delete; 92 | }; 93 | 94 | } // namespace classp 95 | 96 | #endif // LEXER_BASE_H_ 97 | -------------------------------------------------------------------------------- /src/skeleton.h: -------------------------------------------------------------------------------- 1 | @# This file is a part of the Classp parser, formatter, and AST generator. 2 | @# Description: Skeleton header file used to generate class definition headers. 3 | @# 4 | @# Copyright 2015 Google Inc. 5 | @# 6 | @# Licensed under the Apache License, Version 2.0 (the "License"); 7 | @# you may not use this file except in compliance with the License. 8 | @# You may obtain a copy of the License at 9 | @# 10 | @# http://www.apache.org/licenses/LICENSE-2.0 11 | @# 12 | @# Unless required by applicable law or agreed to in writing, software 13 | @# distributed under the License is distributed on an "AS IS" BASIS, 14 | @# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | @# See the License for the specific language governing permissions and 16 | @# limitations under the License. 17 | @# 18 | /* BEGIN HEADER */ 19 | #ifndef @ModuleNameUpper()@_INCLUDE_ 20 | #define @ModuleNameUpper()@_INCLUDE_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "classp.h" 27 | 28 | // Include files generated by bison 29 | #include "@ModuleName()@.yacc.hh" 30 | #include "location.hh" 31 | #include "position.hh" 32 | 33 | namespace @NamespaceName()@ { 34 | using std::istream; 35 | using std::ostream; 36 | using classp::classpPrint; 37 | using classp::classpFormat; 38 | using classp::AttributeMap; 39 | 40 | // Location and state information from the parser. 41 | typedef location ParseState; 42 | 43 | class AstNode; 44 | /* BEGIN FORWARD DECLARATIONS */ 45 | @@PrintForwardDeclarations(out);@@ 46 | /* END FORWARD DECLARATIONS */ 47 | 48 | // Base class for @NamespaceName()@ AST nodes 49 | class AstNode : public classp::ClasspNode { 50 | public: 51 | string className() override { return "AstNode"; } 52 | AstNode(ParseState parseState) 53 | : parseState(parseState) { 54 | } 55 | 56 | // Write out a bracketed form of this AST from the declared syntax. 57 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 58 | assert(false); 59 | } 60 | 61 | ParseState parseState; 62 | }; 63 | 64 | /* BEGIN CLASS DEFINITIONS */ 65 | @@PrintClassDefinitions(out);@@ 66 | /* END CLASS DEFINITIONS */ 67 | 68 | } // namespace @NamespaceName()@ 69 | #endif // @ModuleNameUpper()@_INCLUDE_ 70 | 71 | /* END HEADER */ 72 | -------------------------------------------------------------------------------- /src/skeleton.sed: -------------------------------------------------------------------------------- 1 | # This file is a part of the Classp parser, formatter, and AST generator. 2 | # Description: Used to generate skeleton-generator.h from the skeleton files. 3 | # 4 | # Copyright 2015 Google Inc. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | # skip any lines with the skeleton comment marker "@#" 19 | /^@#/d 20 | 21 | # put a backslash in front of any backslashes or double quotes 22 | /@@.*@@/!s/\\/\\\\/g 23 | /@@.*@@/!s/"/\\"/g 24 | 25 | # put the line inside double quotes with a newline at the end 26 | /@@.*@@/!s/.*/ "&\\n"/ 27 | 28 | # replace any references to "@expr@" with code to evaluate and insert expr 29 | /@@.*@@/!s/@\([^@][^@]*\)@/" << \1 << "/g 30 | 31 | # handle any blank lines 32 | /^ *$/c\ 33 | "\\n" 34 | 35 | # print a file header 36 | 1i\ 37 | /* THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT EDIT IT. */ 38 | 39 | # Generate code to create and end the print functions 40 | /BEGIN LEXER/c\ 41 | \ 42 | void ParserBase::PrintLexer(ostream& out) {\ 43 | out <<\ 44 | "/* BEGIN LEXER */\\n" 45 | 46 | /END LEXER/c\ 47 | "/* END LEXER */\\n";\ 48 | } 49 | 50 | /BEGIN PARSER/c\ 51 | \ 52 | void ParserBase::PrintParser(ostream& out) {\ 53 | out <<\ 54 | "/* BEGIN PARSER */\\n" 55 | 56 | /END PARSER/c\ 57 | "/* END PARSER */\\n";\ 58 | } 59 | 60 | /BEGIN HEADER/c\ 61 | \ 62 | void ParserBase::PrintHFile(ostream& out) {\ 63 | out << \ 64 | "/* BEGIN HEADER */\\n" 65 | 66 | /END HEADER/c\ 67 | "/* END HEADER */\\n";\ 68 | } 69 | 70 | # Generate code to add the inline function calls 71 | /^ *@@/s/^\( *\)@@\(.*\)@@/ ;\n\1\2\n\1out < 20 | #include 21 | #include 22 | #include // For va_list and related operations 23 | #include 24 | #include // MSVC requires this for _vsnprintf 25 | #include 26 | 27 | #ifdef COMPILER_MSVC 28 | enum { IS_COMPILER_MSVC = 1 }; 29 | #else 30 | enum { IS_COMPILER_MSVC = 0 }; 31 | #endif 32 | 33 | void StringAppendV(string* dst, const char* format, va_list ap) { 34 | // First try with a small fixed size buffer 35 | static const int kSpaceLength = 1024; 36 | char space[kSpaceLength]; 37 | 38 | // It's possible for methods that use a va_list to invalidate 39 | // the data in it upon use. The fix is to make a copy 40 | // of the structure before using it and use that copy instead. 41 | va_list backup_ap; 42 | va_copy(backup_ap, ap); 43 | int result = vsnprintf(space, kSpaceLength, format, backup_ap); 44 | va_end(backup_ap); 45 | 46 | if (result < kSpaceLength) { 47 | if (result >= 0) { 48 | // Normal case -- everything fit. 49 | dst->append(space, result); 50 | return; 51 | } 52 | 53 | if (IS_COMPILER_MSVC) { 54 | // Error or MSVC running out of space. MSVC 8.0 and higher 55 | // can be asked about space needed with the special idiom below: 56 | va_copy(backup_ap, ap); 57 | result = vsnprintf(NULL, 0, format, backup_ap); 58 | va_end(backup_ap); 59 | } 60 | 61 | if (result < 0) { 62 | // Just an error. 63 | return; 64 | } 65 | } 66 | 67 | // Increase the buffer size to the size requested by vsnprintf, 68 | // plus one for the closing \0. 69 | int length = result + 1; 70 | char* buf = new char[length]; 71 | 72 | // Restore the va_list before we use it again 73 | va_copy(backup_ap, ap); 74 | result = vsnprintf(buf, length, format, backup_ap); 75 | va_end(backup_ap); 76 | 77 | if (result >= 0 && result < length) { 78 | // It fit 79 | dst->append(buf, result); 80 | } 81 | delete[] buf; 82 | } 83 | 84 | string StringPrintf(const char* format, ...) { 85 | va_list ap; 86 | va_start(ap, format); 87 | string result; 88 | StringAppendV(&result, format, ap); 89 | va_end(ap); 90 | return result; 91 | } 92 | 93 | const string& SStringPrintf(string* dst, const char* format, ...) { 94 | va_list ap; 95 | va_start(ap, format); 96 | dst->clear(); 97 | StringAppendV(dst, format, ap); 98 | va_end(ap); 99 | return *dst; 100 | } 101 | 102 | void StringAppendF(string* dst, const char* format, ...) { 103 | va_list ap; 104 | va_start(ap, format); 105 | StringAppendV(dst, format, ap); 106 | va_end(ap); 107 | } 108 | 109 | // Max arguments supported by StringPrintVector 110 | const int kStringPrintfVectorMaxArgs = 32; 111 | 112 | // An empty block of zero for filler arguments. This is const so that if 113 | // printf tries to write to it (via %n) then the program gets a SIGSEGV 114 | // and we can fix the problem or protect against an attack. 115 | static const char string_printf_empty_block[256] = {'\0'}; 116 | 117 | string StringPrintfVector(const char* format, const std::vector& v) { 118 | if (v.size() > kStringPrintfVectorMaxArgs) { 119 | std::cerr << "StringPrintfVector currently only supports up to " 120 | << kStringPrintfVectorMaxArgs << " arguments. "; 121 | exit(1); 122 | } 123 | 124 | // Add filler arguments so that bogus format+args have a harder time 125 | // crashing the program, corrupting the program (%n), 126 | // or displaying random chunks of memory to users. 127 | 128 | const char* cstr[kStringPrintfVectorMaxArgs]; 129 | for (int i = 0; i < v.size(); ++i) { 130 | cstr[i] = v[i].c_str(); 131 | } 132 | for (int i = v.size(); i < kStringPrintfVectorMaxArgs; ++i) { 133 | cstr[i] = &string_printf_empty_block[0]; 134 | } 135 | 136 | // I do not know any way to pass kStringPrintfVectorMaxArgs arguments, 137 | // or any way to build a va_list by hand, or any API for printf 138 | // that accepts an array of arguments. The best I can do is stick 139 | // this COMPILE_ASSERT right next to the actual statement. 140 | 141 | assert(kStringPrintfVectorMaxArgs == 32); 142 | return StringPrintf( 143 | format, cstr[0], cstr[1], cstr[2], cstr[3], cstr[4], cstr[5], cstr[6], 144 | cstr[7], cstr[8], cstr[9], cstr[10], cstr[11], cstr[12], cstr[13], 145 | cstr[14], cstr[15], cstr[16], cstr[17], cstr[18], cstr[19], cstr[20], 146 | cstr[21], cstr[22], cstr[23], cstr[24], cstr[25], cstr[26], cstr[27], 147 | cstr[28], cstr[29], cstr[30], cstr[31]); 148 | } 149 | -------------------------------------------------------------------------------- /src/stringprintf.h: -------------------------------------------------------------------------------- 1 | // Copyright 2002 Google Inc. 2 | // Printf variants that place their output in a C++ string. 3 | // 4 | // Usage: 5 | // string result = StringPrintf("%d %s\n", 10, "hello"); 6 | // SStringPrintf(&result, "%d %s\n", 10, "hello"); 7 | // StringAppendF(&result, "%d %s\n", 20, "there"); 8 | /* 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | */ 22 | 23 | #ifndef BASE_STRINGPRINTF_H_ 24 | #define BASE_STRINGPRINTF_H_ 25 | 26 | #include 27 | #include 28 | using std::string; 29 | #include 30 | 31 | #define PRINTF_ATTRIBUTE(string_index, first_to_check) \ 32 | __attribute__((__format__(__printf__, string_index, first_to_check))) 33 | 34 | // Return a C++ string 35 | extern string StringPrintf(const char* format, ...) 36 | // Tell the compiler to do printf format string checking. 37 | PRINTF_ATTRIBUTE(1, 2); 38 | 39 | // Store result into a supplied string and return it 40 | extern const string& SStringPrintf(string* dst, const char* format, ...) 41 | // Tell the compiler to do printf format string checking. 42 | PRINTF_ATTRIBUTE(2, 3); 43 | 44 | // Append result to a supplied string 45 | extern void StringAppendF(string* dst, const char* format, ...) 46 | // Tell the compiler to do printf format string checking. 47 | PRINTF_ATTRIBUTE(2, 3); 48 | 49 | // Lower-level routine that takes a va_list and appends to a specified 50 | // string. All other routines are just convenience wrappers around it. 51 | extern void StringAppendV(string* dst, const char* format, va_list ap); 52 | 53 | // The max arguments supported by StringPrintfVector 54 | extern const int kStringPrintfVectorMaxArgs; 55 | 56 | // You can use this version when all your arguments are strings, but 57 | // you don't know how many arguments you'll have at compile time. 58 | // StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs 59 | extern string StringPrintfVector(const char* format, 60 | const std::vector& v); 61 | 62 | #endif // BASE_STRINGPRINTF_H_ 63 | -------------------------------------------------------------------------------- /src/stub-main.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Classp parser, formatter, and AST generator. 3 | * Description: A stub main used to test the library builds. 4 | * 5 | * Copyright 2015 Google Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | */ 20 | #include "t1.h" 21 | #include 22 | #include 23 | 24 | int main(int argc, char** argv) { 25 | std::stringstream in("a x 2 y 3 b x 4 y 5 c x 6 z 7"); 26 | t1::AstNode* result = t1::D::parse(in, std::cout); 27 | if (result) { 28 | std::cout << "Succeeded:\n"; 29 | result->format(std::cout); 30 | std::cout << "\n"; 31 | } else { 32 | std::cout << "Parse failed.\n"; 33 | return 1; 34 | } 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This file is a part of the Classp parser, formatter, and AST generator. 4 | # 5 | # Copyright 2015 Google Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | 20 | # usage: test.sh * [ --run ] * 21 | # for each file f in * copy the file from ../tests to a tmp directory 22 | # and run classp on it, then compare the generated files to the golden files in 23 | # ../tests. If --run is seen, then for all following files, also build them 24 | # with -DPARSER_TEST (this causes generation of an executable that will run 25 | # the samples given in the source file), then run the samples test. 26 | 27 | compare_parse=1 28 | run_tests=0 29 | do_updates=0 30 | errors=0 31 | 32 | TESTDIR=/tmp/classp-test 33 | CLASSP=`pwd`/classp 34 | INC=`cd ../include && pwd` 35 | GOLD=../tests 36 | 37 | function check-and-update() { 38 | if [[ ! -a $1 ]] ; then return ; fi 39 | if ( ! diff --brief $1 $2 >&/dev/null ) ; then 40 | echo UPDATING $2 41 | if [[ -a $2 && -n $CHECKOUT ]] ; then 42 | # the gold file exists and there is a checkout command defined 43 | $CHECKOUT $2 44 | fi 45 | cp $1 $2 46 | fi 47 | } 48 | 49 | if [[ $1 == -U ]] ; then 50 | # update files that are already generated 51 | compare_parse=0 52 | run_tests=0 53 | do_updates=1 54 | shift 55 | else 56 | mkdir -p $TESTDIR 57 | rm -f $TESTDIR/* 58 | fi 59 | 60 | for f in $* ; do 61 | case $f in 62 | (-rc|-cr) 63 | compare_parse=1 64 | run_tests=1 65 | continue 66 | ;; 67 | (-c) 68 | compare_parse=1 69 | run_tests=0 70 | continue 71 | ;; 72 | (-r) 73 | compare_parse=0 74 | run_tests=1 75 | continue 76 | ;; 77 | (-Uc) 78 | # build files and update the changed ones 79 | compare_parse=1 80 | run_tests=0 81 | do_updates=1 82 | continue 83 | ;; 84 | esac 85 | if (( compare_parse || run_tests )) ; then 86 | # copy the test to a temp dir and run classp on it 87 | cp $GOLD/$f $TESTDIR 88 | if (( $? )) ; then 89 | echo "Missing test '$f'" 90 | ((errors+=1)) 91 | continue 92 | fi 93 | echo "--- parsing $f ---" 94 | $CLASSP $TESTDIR/$f 95 | if (( $? )) ; then 96 | # generation of the classp files failed 97 | ((errors+=1)) 98 | continue 99 | fi 100 | fi 101 | if (( do_updates )) ; then 102 | for out in $TESTDIR/$f.[hly] ; do 103 | check-and-update $out $GOLD/`basename $out` 104 | done 105 | if [[ -a $GOLD/$f.out ]] ; then 106 | # there is a .out file recorded so copy it as well 107 | check-and-update $TESTDIR/$f.out $GOLD/$f.out 108 | fi 109 | elif (( compare_parse )) ; then 110 | # compare all of the test output files 111 | for out in $TESTDIR/$f.[hly] ; do 112 | diff --brief $out $GOLD/`basename $out` 113 | ((errors+=$?)) 114 | done 115 | fi 116 | if (( run_tests )) ; then 117 | # build and run the samples 118 | echo "--- building and running $f ---" 119 | ( \ 120 | cd $TESTDIR && \ 121 | bison -o $f.yacc.cc $f.y && \ 122 | flex -o $f.lex.cc $f.l && \ 123 | g++ -g -o $f.exe -std=c++11 -I$INC -Wall -DPARSER_TEST \ 124 | $f.yacc.cc $f.lex.cc && \ 125 | ./$f.exe --samples ; \ 126 | ) >$TESTDIR/$f.out 127 | cond=$? 128 | if [[ -a $TESTDIR/$f.out && -a $GOLD/$f.out ]] ; then 129 | # if there is a .out file recorded, then ignore errors in the run 130 | # and only show errors if there is a diff in the .out files. 131 | diff --brief $TESTDIR/$f.out $GOLD/$f.out 132 | ((errors+=$?)) 133 | elif (( $cond )) ; then 134 | # show an error if any of the building and running steps failed 135 | echo "$f failed the samples test" 136 | ((errors+=1)) 137 | fi 138 | fi 139 | done 140 | if ((do_updates)) ; then 141 | true 142 | elif ((errors)) ; then 143 | echo "$errors ERRORS" 144 | else 145 | echo "all tests passed" 146 | fi 147 | -------------------------------------------------------------------------------- /tests/alt1: -------------------------------------------------------------------------------- 1 | // This is a bug. In (a|b) it says that an empty alternate must be 2 | // present, but since this whole thing occurs in a higher alternation 3 | // that does have an empty alternate, it should work. If neither a 4 | // nor b is present, then print the empty alternate from the outer 5 | // alternation. 6 | class A { 7 | optional int a; 8 | optional int b; 9 | syntax('a' ('b' (a|b)|)); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /tests/assign1: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class B { 20 | bool b; 21 | syntax(b{true->'t'|false->'f'}); 22 | } 23 | class I { 24 | int i; 25 | syntax(i{1->'one'|2->'two'}); 26 | } 27 | class S { 28 | string s; 29 | syntax(s{'1'->'one'|'2'->'two'}); 30 | } 31 | 32 | class B2 { 33 | bool b; 34 | syntax(b{true->'t'|false->}); 35 | } 36 | 37 | class D { 38 | %parseable; 39 | B b; 40 | I i; 41 | S s; 42 | B2 b2; 43 | syntax('B' b 'I' i 'S' s 'B2' b2 'done'); 44 | sample('B t I two S one B2 done', '(D b:(B b:true) i:(I i:2) s:(S s:1) b2:(B2 b:false))'); 45 | sample('B f I one S two B2 t done', '(D b:(B b:false) i:(I i:1) s:(S s:2) b2:(B2 b:true))'); 46 | } -------------------------------------------------------------------------------- /tests/assign1.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef assign1_INCLUDE_ 3 | #define assign1_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "assign1.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace assign1 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class B; 29 | class B2; 30 | class D; 31 | class I; 32 | class S; 33 | /* END FORWARD DECLARATIONS */ 34 | 35 | // Base class for assign1 AST nodes 36 | class AstNode : public classp::ClasspNode { 37 | public: 38 | string className() override { return "AstNode"; } 39 | AstNode(ParseState parseState) 40 | : parseState(parseState) { 41 | } 42 | 43 | // Write out a bracketed form of this AST from the declared syntax. 44 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 45 | assert(false); 46 | } 47 | 48 | ParseState parseState; 49 | }; 50 | 51 | /* BEGIN CLASS DEFINITIONS */ 52 | class B: public AstNode { 53 | public: 54 | string className() override { return "B"; } 55 | B(ParseState parseState, bool b); 56 | void printMembers(ostream& out) override; 57 | void format(ostream& out, int precedence) override; 58 | 59 | bool b; 60 | }; 61 | 62 | class I: public AstNode { 63 | public: 64 | string className() override { return "I"; } 65 | I(ParseState parseState, int i); 66 | void printMembers(ostream& out) override; 67 | void format(ostream& out, int precedence) override; 68 | 69 | int i; 70 | }; 71 | 72 | class S: public AstNode { 73 | public: 74 | string className() override { return "S"; } 75 | S(ParseState parseState, string s); 76 | void printMembers(ostream& out) override; 77 | void format(ostream& out, int precedence) override; 78 | 79 | string s; 80 | }; 81 | 82 | class B2: public AstNode { 83 | public: 84 | string className() override { return "B2"; } 85 | B2(ParseState parseState, bool b); 86 | void printMembers(ostream& out) override; 87 | void format(ostream& out, int precedence) override; 88 | 89 | bool b; 90 | }; 91 | 92 | class D: public AstNode { 93 | public: 94 | string className() override { return "D"; } 95 | D(ParseState parseState, B* b, I* i, S* s, B2* b2); 96 | static D* parse(istream& input, ostream& errors); 97 | void printMembers(ostream& out) override; 98 | void format(ostream& out, int precedence) override; 99 | 100 | B* b = nullptr; 101 | I* i = nullptr; 102 | S* s = nullptr; 103 | B2* b2 = nullptr; 104 | }; 105 | /* END CLASS DEFINITIONS */ 106 | 107 | } // namespace assign1 108 | #endif // assign1_INCLUDE_ 109 | 110 | /* END HEADER */ 111 | -------------------------------------------------------------------------------- /tests/calculator1: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class Expression { 20 | %parseable; 21 | syntax('(' self ')'); 22 | sample('4-1+-2*5', print); 23 | sample('-(5*6)', print); 24 | sample('4-1+-2 5', print); 25 | sample('-(5 6)', print); 26 | } 27 | 28 | class Negate: Expression { 29 | Expression arg; 30 | syntax('-' arg) %left 3; 31 | } 32 | 33 | class Binop: Expression { 34 | Expression arg1; 35 | Expression arg2; 36 | } 37 | 38 | class Sum: Binop { 39 | syntax(arg1 '+' arg2) %left 1; 40 | } 41 | 42 | class Diff: Binop { 43 | syntax(arg1 '-' arg2) %left 1; 44 | } 45 | 46 | class Prod: Binop { 47 | syntax(arg1 '*' arg2) %left 2; 48 | syntax(arg1 arg2) %left 2; 49 | } 50 | 51 | class Div: Binop { 52 | syntax(arg1 '/' arg2) %left 2; 53 | } 54 | 55 | class IntegerLiteral: Expression { 56 | int n; 57 | syntax(n); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /tests/calculator1.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef calculator1_INCLUDE_ 3 | #define calculator1_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "calculator1.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace calculator1 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class Binop; 29 | class Diff; 30 | class Div; 31 | class Expression; 32 | class IntegerLiteral; 33 | class Negate; 34 | class Prod; 35 | class Sum; 36 | /* END FORWARD DECLARATIONS */ 37 | 38 | // Base class for calculator1 AST nodes 39 | class AstNode : public classp::ClasspNode { 40 | public: 41 | string className() override { return "AstNode"; } 42 | AstNode(ParseState parseState) 43 | : parseState(parseState) { 44 | } 45 | 46 | // Write out a bracketed form of this AST from the declared syntax. 47 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 48 | assert(false); 49 | } 50 | 51 | ParseState parseState; 52 | }; 53 | 54 | /* BEGIN CLASS DEFINITIONS */ 55 | class Expression: public AstNode { 56 | public: 57 | string className() override { return "Expression"; } 58 | Expression(ParseState parseState); 59 | static Expression* parse(istream& input, ostream& errors); 60 | void printMembers(ostream& out) override; 61 | void bracketFormat(ostream& out, AstNode* self) override; 62 | 63 | }; 64 | 65 | class Negate: public Expression { 66 | public: 67 | string className() override { return "Negate"; } 68 | Negate(ParseState parseState, Expression* arg); 69 | void printMembers(ostream& out) override; 70 | void format(ostream& out, int precedence) override; 71 | 72 | Expression* arg = nullptr; 73 | }; 74 | 75 | class Binop: public Expression { 76 | public: 77 | string className() override { return "Binop"; } 78 | Binop(ParseState parseState, Expression* arg1, Expression* arg2); 79 | void printMembers(ostream& out) override; 80 | 81 | Expression* arg1 = nullptr; 82 | Expression* arg2 = nullptr; 83 | }; 84 | 85 | class Sum: public Binop { 86 | public: 87 | string className() override { return "Sum"; } 88 | Sum(ParseState parseState, Expression* arg1, Expression* arg2); 89 | void printMembers(ostream& out) override; 90 | void format(ostream& out, int precedence) override; 91 | 92 | }; 93 | 94 | class Diff: public Binop { 95 | public: 96 | string className() override { return "Diff"; } 97 | Diff(ParseState parseState, Expression* arg1, Expression* arg2); 98 | void printMembers(ostream& out) override; 99 | void format(ostream& out, int precedence) override; 100 | 101 | }; 102 | 103 | class Prod: public Binop { 104 | public: 105 | string className() override { return "Prod"; } 106 | Prod(ParseState parseState, Expression* arg1, Expression* arg2); 107 | void printMembers(ostream& out) override; 108 | void format(ostream& out, int precedence) override; 109 | 110 | }; 111 | 112 | class Div: public Binop { 113 | public: 114 | string className() override { return "Div"; } 115 | Div(ParseState parseState, Expression* arg1, Expression* arg2); 116 | void printMembers(ostream& out) override; 117 | void format(ostream& out, int precedence) override; 118 | 119 | }; 120 | 121 | class IntegerLiteral: public Expression { 122 | public: 123 | string className() override { return "IntegerLiteral"; } 124 | IntegerLiteral(ParseState parseState, int n); 125 | void printMembers(ostream& out) override; 126 | void format(ostream& out, int precedence) override; 127 | 128 | int n; 129 | }; 130 | /* END CLASS DEFINITIONS */ 131 | 132 | } // namespace calculator1 133 | #endif // calculator1_INCLUDE_ 134 | 135 | /* END HEADER */ 136 | -------------------------------------------------------------------------------- /tests/classp_lang: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | @@' 20 | enum Associativity{AssocLeft, AssocRight, AssocNassoc}; 21 | enum SampleCheck {ExpectSucceed, ExpectFailure, PrintResult, CompareResult}; 22 | '@@ 23 | class Declarations { 24 | %parseable; 25 | ClassDefinition decl[]; 26 | syntax ( decl* ); 27 | sample("class A {%parseable;int n;syntax ('+' n);sample ('+ 3');}", print); 28 | } 29 | 30 | class ClassDefinition { 31 | identifier class_name; 32 | optional identifier parent_name; 33 | AttributeDeclaration attributes[]; 34 | SyntaxDeclaration syntax_decl[]; 35 | SampleDeclaration sample_decl[]; 36 | bool parseable default false syntax(self{true->'%parseable' ';'}); 37 | syntax ('class' class_name (':' parent_name|) 38 | '{' ((attributes|syntax_decl|sample_decl|parseable)*) '}'); 39 | } 40 | 41 | class AttributeDeclaration { 42 | bool is_optional default false syntax(self{true->'optional'}|); 43 | identifier attribute_name; 44 | identifier type_name; 45 | optional Expression default_value syntax('default' self|); 46 | bool is_array default false syntax(self{true->'[' ']'}); 47 | optional SyntaxDeclaration syntax_decl syntax('syntax' '(' self ')'|); 48 | syntax(is_optional type_name attribute_name (default_value|is_array|) syntax_decl ';'); 49 | } 50 | 51 | class SyntaxDeclaration { 52 | Pattern pattern; 53 | optional Associativity assoc syntax(self{AssocLeft->'left' 54 | |AssocRight->'right' 55 | |AssocNassoc->'nassoc' 56 | |AssocLeft->'assoc'}); 57 | optional int precedence; 58 | syntax('syntax' '(' pattern ')' ('%' assoc precedence|)); 59 | } 60 | 61 | class Pattern { 62 | syntax('(' self ')'); 63 | } 64 | 65 | class Alternation: Pattern { 66 | Pattern alternates[]; 67 | syntax(alternates*'|') %assoc 1; 68 | } 69 | 70 | class Iterator: Pattern { 71 | Pattern pattern1; 72 | Pattern pattern2; 73 | } 74 | 75 | class Iterator0OrMore:Iterator { 76 | syntax(pattern1 '*' pattern2) %nassoc 2; 77 | } 78 | 79 | class Iterator1OrMore:Iterator { 80 | syntax(pattern1 '+' pattern2) %nassoc 2; 81 | } 82 | 83 | class PatternSequence: Pattern { 84 | Pattern list[]; 85 | syntax(list*) %assoc 3; 86 | } 87 | 88 | class CasePattern: Pattern { 89 | identifier attribute; 90 | Pattern patterns[]; 91 | Expression exprs[]; 92 | syntax(attribute '{' (exprs '->' patterns + '|') '}'); 93 | } 94 | 95 | class Expression { 96 | identifier id; 97 | syntax(id); 98 | } 99 | 100 | class SampleDeclaration { 101 | string sample_decl; 102 | optional string expected; 103 | SampleCheck check default ExpectSucceed syntax(self 104 | {ExpectSucceed->'succeed' 105 | |ExpectFailure->'fail' 106 | |PrintResult->'print' 107 | |CompareResult->}); 108 | syntax('sample' '(' sample_decl ',' (expected|check) ')'); 109 | } 110 | 111 | -------------------------------------------------------------------------------- /tests/classp_lang.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef classp_lang_INCLUDE_ 3 | #define classp_lang_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "classp_lang.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace classp_lang { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class Alternation; 29 | class AttributeDeclaration; 30 | class CasePattern; 31 | class ClassDefinition; 32 | class Declarations; 33 | class Expression; 34 | class Iterator; 35 | class Iterator0OrMore; 36 | class Iterator1OrMore; 37 | class Pattern; 38 | class PatternSequence; 39 | class SampleDeclaration; 40 | class SyntaxDeclaration; 41 | /* END FORWARD DECLARATIONS */ 42 | 43 | // Base class for classp_lang AST nodes 44 | class AstNode : public classp::ClasspNode { 45 | public: 46 | string className() override { return "AstNode"; } 47 | AstNode(ParseState parseState) 48 | : parseState(parseState) { 49 | } 50 | 51 | // Write out a bracketed form of this AST from the declared syntax. 52 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 53 | assert(false); 54 | } 55 | 56 | ParseState parseState; 57 | }; 58 | 59 | /* BEGIN CLASS DEFINITIONS */ 60 | class Declarations: public AstNode { 61 | public: 62 | string className() override { return "Declarations"; } 63 | Declarations(ParseState parseState, vector decl); 64 | static Declarations* parse(istream& input, ostream& errors); 65 | void printMembers(ostream& out) override; 66 | void format(ostream& out, int precedence) override; 67 | 68 | vector decl; 69 | }; 70 | 71 | class ClassDefinition: public AstNode { 72 | public: 73 | string className() override { return "ClassDefinition"; } 74 | ClassDefinition(ParseState parseState, identifier class_name, AttributeMap& keyword_args); 75 | void printMembers(ostream& out) override; 76 | void format(ostream& out, int precedence) override; 77 | 78 | identifier class_name; 79 | identifier parent_name; 80 | vector attributes; 81 | vector syntax_decl; 82 | vector sample_decl; 83 | bool parseable; 84 | bool has_parent_name = false; 85 | }; 86 | 87 | class AttributeDeclaration: public AstNode { 88 | public: 89 | string className() override { return "AttributeDeclaration"; } 90 | AttributeDeclaration(ParseState parseState, identifier attribute_name, identifier type_name, AttributeMap& keyword_args); 91 | void printMembers(ostream& out) override; 92 | void format(ostream& out, int precedence) override; 93 | 94 | bool is_optional; 95 | identifier attribute_name; 96 | identifier type_name; 97 | Expression* default_value = nullptr; 98 | bool is_array; 99 | SyntaxDeclaration* syntax_decl = nullptr; 100 | bool has_default_value = false; 101 | bool has_syntax_decl = false; 102 | }; 103 | 104 | class SyntaxDeclaration: public AstNode { 105 | public: 106 | string className() override { return "SyntaxDeclaration"; } 107 | SyntaxDeclaration(ParseState parseState, Pattern* pattern, AttributeMap& keyword_args); 108 | void printMembers(ostream& out) override; 109 | void format(ostream& out, int precedence) override; 110 | 111 | Pattern* pattern = nullptr; 112 | Associativity assoc; 113 | int precedence; 114 | bool has_assoc = false; 115 | bool has_precedence = false; 116 | }; 117 | 118 | class Pattern: public AstNode { 119 | public: 120 | string className() override { return "Pattern"; } 121 | Pattern(ParseState parseState); 122 | void printMembers(ostream& out) override; 123 | void bracketFormat(ostream& out, AstNode* self) override; 124 | 125 | }; 126 | 127 | class Alternation: public Pattern { 128 | public: 129 | string className() override { return "Alternation"; } 130 | Alternation(ParseState parseState, vector alternates); 131 | void printMembers(ostream& out) override; 132 | void format(ostream& out, int precedence) override; 133 | 134 | vector alternates; 135 | }; 136 | 137 | class Iterator: public Pattern { 138 | public: 139 | string className() override { return "Iterator"; } 140 | Iterator(ParseState parseState, Pattern* pattern1, Pattern* pattern2); 141 | void printMembers(ostream& out) override; 142 | 143 | Pattern* pattern1 = nullptr; 144 | Pattern* pattern2 = nullptr; 145 | }; 146 | 147 | class Iterator0OrMore: public Iterator { 148 | public: 149 | string className() override { return "Iterator0OrMore"; } 150 | Iterator0OrMore(ParseState parseState, Pattern* pattern1, Pattern* pattern2); 151 | void printMembers(ostream& out) override; 152 | void format(ostream& out, int precedence) override; 153 | 154 | }; 155 | 156 | class Iterator1OrMore: public Iterator { 157 | public: 158 | string className() override { return "Iterator1OrMore"; } 159 | Iterator1OrMore(ParseState parseState, Pattern* pattern1, Pattern* pattern2); 160 | void printMembers(ostream& out) override; 161 | void format(ostream& out, int precedence) override; 162 | 163 | }; 164 | 165 | class PatternSequence: public Pattern { 166 | public: 167 | string className() override { return "PatternSequence"; } 168 | PatternSequence(ParseState parseState, vector list); 169 | void printMembers(ostream& out) override; 170 | void format(ostream& out, int precedence) override; 171 | 172 | vector list; 173 | }; 174 | 175 | class CasePattern: public Pattern { 176 | public: 177 | string className() override { return "CasePattern"; } 178 | CasePattern(ParseState parseState, identifier attribute, AttributeMap& keyword_args); 179 | void printMembers(ostream& out) override; 180 | void format(ostream& out, int precedence) override; 181 | 182 | identifier attribute; 183 | vector patterns; 184 | vector exprs; 185 | }; 186 | 187 | class Expression: public AstNode { 188 | public: 189 | string className() override { return "Expression"; } 190 | Expression(ParseState parseState, identifier id); 191 | void printMembers(ostream& out) override; 192 | void format(ostream& out, int precedence) override; 193 | 194 | identifier id; 195 | }; 196 | 197 | class SampleDeclaration: public AstNode { 198 | public: 199 | string className() override { return "SampleDeclaration"; } 200 | SampleDeclaration(ParseState parseState, string sample_decl, AttributeMap& keyword_args); 201 | void printMembers(ostream& out) override; 202 | void format(ostream& out, int precedence) override; 203 | 204 | string sample_decl; 205 | string expected; 206 | SampleCheck check; 207 | bool has_expected = false; 208 | }; 209 | /* END CLASS DEFINITIONS */ 210 | 211 | } // namespace classp_lang 212 | #endif // classp_lang_INCLUDE_ 213 | 214 | /* END HEADER */ 215 | -------------------------------------------------------------------------------- /tests/example.y: -------------------------------------------------------------------------------- 1 | /* BEGIN PARSER */ 2 | %code requires { 3 | 4 | #include 5 | using std::string; 6 | #include 7 | using std::vector; 8 | 9 | #include "classp.h" 10 | 11 | namespace example { 12 | class ParseDriver; 13 | class AstNode; 14 | /* BEGIN FORWARD DECLARATIONS */ 15 | class Expression; 16 | class IntegerLiteral; 17 | class Variable; 18 | /* END FORWARD DECLARATIONS */ 19 | } 20 | 21 | } 22 | 23 | %require "3.0.2" 24 | %defines 25 | %define api.value.type variant 26 | %define "parser_class_name" {YYParser} 27 | %error-verbose 28 | %lex-param {example::ParseDriver* parser} 29 | %locations 30 | %define api.namespace {example} 31 | %parse-param {example::ParseDriver* parser} 32 | %parse-param {example::AstNode** result} 33 | %define api.token.constructor 34 | %skeleton "lalr1.cc" 35 | 36 | %initial-action { 37 | } 38 | 39 | %token TOK_EOF 0 "end of file" 40 | 41 | /* BEGIN GENERATED TOKEN DECLARATIONS */ 42 | /* END GENERATED TOKEN DECLARATIONS */ 43 | 44 | %token TOK_IDENTIFIER "identifier" 45 | %token TOK_INT64 "integer literal" 46 | %token TOK_STRING_LITERAL "string literal" 47 | 48 | 49 | /* BEGIN NONTERMINAL TYPES */ 50 | %type class_Expression 51 | %type class_IntegerLiteral 52 | %type class_Variable 53 | /* END NONTERMINAL TYPES */ 54 | 55 | %type TOK_INT64 56 | %type TOK_IDENTIFIER 57 | %type TOK_STRING_LITERAL 58 | 59 | %code { 60 | 61 | #include "example.yacc.hh" 62 | #include "example-driver.h" 63 | #include "example.h" 64 | 65 | namespace example { 66 | 67 | static inline YYParser::symbol_type yylex(ParseDriver* parser) { 68 | return parser->lexer_->NextToken(parser); 69 | } 70 | 71 | } // namespace example 72 | 73 | } 74 | 75 | 76 | %start start 77 | 78 | %% 79 | 80 | start 81 | /* BEGIN PARSEABLE */ 82 | : class_Expression TOK_EOF { *result = $1; } 83 | /* END PARSEABLE */ 84 | ; 85 | 86 | /* BEGIN PRODUCTIONS */ 87 | class_Expression 88 | : class_Variable { $$ = $1; } 89 | | class_IntegerLiteral { $$ = $1; } 90 | ; 91 | 92 | class_Variable 93 | : TOK_IDENTIFIER { 94 | $$ = new Variable(@$, $1); } 95 | ; 96 | 97 | class_IntegerLiteral 98 | : TOK_INT64 { 99 | $$ = new IntegerLiteral(@$, $1); } 100 | ; 101 | 102 | /* END PRODUCTIONS */ 103 | 104 | %% 105 | 106 | /* END PARSER */ 107 | -------------------------------------------------------------------------------- /tests/example1: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class Expression { 20 | %parseable; 21 | sample('f()', '(FunctionCall functionName:f argList:[])'); 22 | sample('f(a())', '(FunctionCall functionName:f argList:[(FunctionCall functionName:a argList:[])])'); 23 | sample('f(a(),b(x()),c())', '(FunctionCall functionName:f argList:[(FunctionCall functionName:a argList:[]), (FunctionCall functionName:b argList:[(FunctionCall functionName:x argList:[])]), (FunctionCall functionName:c argList:[])])'); 24 | } 25 | 26 | class FunctionCall: Expression { 27 | identifier functionName; 28 | Expression argList[]; 29 | syntax(functionName '(' (argList*',') ')'); 30 | } 31 | -------------------------------------------------------------------------------- /tests/example1.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef example1_INCLUDE_ 3 | #define example1_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "example1.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace example1 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class Expression; 29 | class FunctionCall; 30 | /* END FORWARD DECLARATIONS */ 31 | 32 | // Base class for example1 AST nodes 33 | class AstNode : public classp::ClasspNode { 34 | public: 35 | string className() override { return "AstNode"; } 36 | AstNode(ParseState parseState) 37 | : parseState(parseState) { 38 | } 39 | 40 | // Write out a bracketed form of this AST from the declared syntax. 41 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 42 | assert(false); 43 | } 44 | 45 | ParseState parseState; 46 | }; 47 | 48 | /* BEGIN CLASS DEFINITIONS */ 49 | class Expression: public AstNode { 50 | public: 51 | string className() override { return "Expression"; } 52 | Expression(ParseState parseState); 53 | static Expression* parse(istream& input, ostream& errors); 54 | void printMembers(ostream& out) override; 55 | 56 | }; 57 | 58 | class FunctionCall: public Expression { 59 | public: 60 | string className() override { return "FunctionCall"; } 61 | FunctionCall(ParseState parseState, identifier functionName, vector argList); 62 | void printMembers(ostream& out) override; 63 | void format(ostream& out, int precedence) override; 64 | 65 | identifier functionName; 66 | vector argList; 67 | }; 68 | /* END CLASS DEFINITIONS */ 69 | 70 | } // namespace example1 71 | #endif // example1_INCLUDE_ 72 | 73 | /* END HEADER */ 74 | -------------------------------------------------------------------------------- /tests/example2: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class Expression { 20 | %parseable; 21 | syntax( '(' self ')' ); 22 | sample('1+2', '(Sum val1:(IntegerLiteral val:1) val2:(IntegerLiteral val:2))'); 23 | sample('1+2*(3+4)', '(Sum val1:(IntegerLiteral val:1) val2:(Product val1:(IntegerLiteral val:2) val2:(Sum val1:(IntegerLiteral val:3) val2:(IntegerLiteral val:4))))'); 24 | sample('(1+2)+(3+4)', '(Sum val1:(Sum val1:(IntegerLiteral val:1) val2:(IntegerLiteral val:2)) val2:(Sum val1:(IntegerLiteral val:3) val2:(IntegerLiteral val:4)))'); 25 | } 26 | 27 | class FunctionCall: Expression { 28 | identifier functionName; 29 | Expression argList[]; 30 | syntax ( functionName '(' (argList*',') ')' ); 31 | } 32 | 33 | class Sum: Expression { 34 | Expression val1; 35 | Expression val2; 36 | syntax (val1 '+' val2) %left 1; 37 | } 38 | 39 | class Product: Expression { 40 | Expression val1; 41 | Expression val2; 42 | syntax (val1 '*' val2) %left 2; 43 | } 44 | 45 | class IntegerLiteral: Expression { 46 | int val; 47 | syntax ( val ); 48 | } 49 | -------------------------------------------------------------------------------- /tests/example2.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef example2_INCLUDE_ 3 | #define example2_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "example2.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace example2 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class Expression; 29 | class FunctionCall; 30 | class IntegerLiteral; 31 | class Product; 32 | class Sum; 33 | /* END FORWARD DECLARATIONS */ 34 | 35 | // Base class for example2 AST nodes 36 | class AstNode : public classp::ClasspNode { 37 | public: 38 | string className() override { return "AstNode"; } 39 | AstNode(ParseState parseState) 40 | : parseState(parseState) { 41 | } 42 | 43 | // Write out a bracketed form of this AST from the declared syntax. 44 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 45 | assert(false); 46 | } 47 | 48 | ParseState parseState; 49 | }; 50 | 51 | /* BEGIN CLASS DEFINITIONS */ 52 | class Expression: public AstNode { 53 | public: 54 | string className() override { return "Expression"; } 55 | Expression(ParseState parseState); 56 | static Expression* parse(istream& input, ostream& errors); 57 | void printMembers(ostream& out) override; 58 | void bracketFormat(ostream& out, AstNode* self) override; 59 | 60 | }; 61 | 62 | class FunctionCall: public Expression { 63 | public: 64 | string className() override { return "FunctionCall"; } 65 | FunctionCall(ParseState parseState, identifier functionName, vector argList); 66 | void printMembers(ostream& out) override; 67 | void format(ostream& out, int precedence) override; 68 | 69 | identifier functionName; 70 | vector argList; 71 | }; 72 | 73 | class Sum: public Expression { 74 | public: 75 | string className() override { return "Sum"; } 76 | Sum(ParseState parseState, Expression* val1, Expression* val2); 77 | void printMembers(ostream& out) override; 78 | void format(ostream& out, int precedence) override; 79 | 80 | Expression* val1 = nullptr; 81 | Expression* val2 = nullptr; 82 | }; 83 | 84 | class Product: public Expression { 85 | public: 86 | string className() override { return "Product"; } 87 | Product(ParseState parseState, Expression* val1, Expression* val2); 88 | void printMembers(ostream& out) override; 89 | void format(ostream& out, int precedence) override; 90 | 91 | Expression* val1 = nullptr; 92 | Expression* val2 = nullptr; 93 | }; 94 | 95 | class IntegerLiteral: public Expression { 96 | public: 97 | string className() override { return "IntegerLiteral"; } 98 | IntegerLiteral(ParseState parseState, int val); 99 | void printMembers(ostream& out) override; 100 | void format(ostream& out, int precedence) override; 101 | 102 | int val; 103 | }; 104 | /* END CLASS DEFINITIONS */ 105 | 106 | } // namespace example2 107 | #endif // example2_INCLUDE_ 108 | 109 | /* END HEADER */ 110 | -------------------------------------------------------------------------------- /tests/expr1: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class Expression { 20 | %parseable; 21 | syntax('(' self ')'); 22 | sample('a + 2', '(PlusOp arg1:(Variable id:a) arg2:(IntegerLiteral val:2)arg3[not defined])'); 23 | sample('a*(2+3=4) < 5', '(LtOp arg1:(TimesOp arg1:(Variable id:a) arg2:(EqOp arg1:(PlusOp arg1:(IntegerLiteral val:2) arg2:(IntegerLiteral val:3)arg3[not defined]) arg2:(IntegerLiteral val:4)arg3[not defined])arg3[not defined]) arg2:(IntegerLiteral val:5)arg3[not defined])'); 24 | sample('1 + case 1 when 1 then 1 else 2 + a end', '(PlusOp arg1:(IntegerLiteral val:1) arg2:(CaseExpression testExpr:(IntegerLiteral val:1) conditions:[(IntegerLiteral val:1)] results:[(IntegerLiteral val:1)] elseResult:(PlusOp arg1:(IntegerLiteral val:2) arg2:(Variable id:a)arg3[not defined]))arg3[not defined])'); 25 | } 26 | 27 | class Variable: Expression { 28 | identifier id; 29 | syntax(id); 30 | } 31 | 32 | class IntegerLiteral: Expression { 33 | int val; 34 | syntax(val); 35 | } 36 | 37 | class CaseExpression: Expression { 38 | Expression testExpr; 39 | Expression conditions[]; 40 | Expression results[]; 41 | Expression elseResult syntax('else' elseResult); 42 | syntax('case' testExpr ('when' conditions 'then' results*) elseResult 'end'); 43 | } 44 | 45 | class Invocation: Expression { 46 | Expression arg1; 47 | optional Expression arg2; 48 | optional Expression arg3; 49 | } 50 | 51 | class OrOp: Invocation { 52 | syntax(arg1 'or' arg2) %left 1; 53 | } 54 | 55 | class AndOp: Invocation { 56 | syntax(arg1 'and' arg2) %left 2; 57 | } 58 | 59 | class NotOp: Invocation { 60 | syntax('not' arg1) %left 3; 61 | } 62 | 63 | class EqOp: Invocation { 64 | syntax(arg1 '=' arg2) %nassoc 4; 65 | } 66 | 67 | class NeOp: Invocation { 68 | syntax(arg1 '!=' arg2) %nassoc 4; 69 | } 70 | 71 | class LtOp: Invocation { 72 | syntax(arg1 '<' arg2) %nassoc 4; 73 | } 74 | 75 | class LeOp: Invocation { 76 | syntax(arg1 '<=' arg2) %nassoc 4; 77 | } 78 | 79 | class GtOp: Invocation { 80 | syntax(arg1 '>' arg2) %nassoc 4; 81 | } 82 | 83 | class GeOp: Invocation { 84 | syntax(arg1 '>=' arg2) %nassoc 4; 85 | } 86 | 87 | // TODO: this creates an ambiguity with the 'and' boolean operation. It should 88 | // be possible to detect this situation and use a precedence production that is 89 | // lower than the one that would cause a conflict with 'and'. 90 | //class BetweenOp: Invocation { 91 | // syntax(arg1 'between' arg2 'and' arg3) %nassoc 4; 92 | //} 93 | 94 | class PlusOp: Invocation { 95 | syntax(arg1 '+' arg2) %left 5; 96 | } 97 | 98 | class MinusOp: Invocation { 99 | syntax(arg1 '-' arg2) %left 5; 100 | } 101 | 102 | class TimesOp: Invocation { 103 | syntax(arg1 '*' arg2) %left 6; 104 | } 105 | 106 | class DivideOp: Invocation { 107 | syntax(arg1 '/' arg2) %left 6; 108 | } 109 | 110 | class NegateOp: Invocation { 111 | syntax('-' arg1) %left 7; 112 | } 113 | 114 | class FunctionCall: Expression { 115 | identifier functionName; 116 | Expression args[]; 117 | syntax(functionName '(' (args*',') ')'); 118 | } 119 | -------------------------------------------------------------------------------- /tests/prec1: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class A { 20 | syntax('(' self ')'); 21 | } 22 | 23 | class Bleft: A { 24 | A a; 25 | syntax('b' a) %left 5; 26 | } 27 | class Cleft: A { 28 | A a; 29 | syntax(a 'c') %left 5; 30 | } 31 | class Dleft: A { 32 | A a1; 33 | A a2; 34 | syntax(a1 'd' a2) %left 5; 35 | } 36 | 37 | class Bright: A { 38 | A a; 39 | syntax('b' a) %right 3; 40 | } 41 | class Cright: A { 42 | A a; 43 | syntax(a 'c') %right 3; 44 | } 45 | class Dright: A { 46 | A a1; 47 | A a2; 48 | syntax(a1 'd' a2) %right 3; 49 | } 50 | 51 | class Bnassoc: A { 52 | A a; 53 | syntax('b' a) %nassoc 2; 54 | } 55 | class Cnassoc: A { 56 | A a; 57 | syntax(a 'c') %nassoc 2; 58 | } 59 | class Dnassoc: A { 60 | A a1; 61 | A a2; 62 | syntax(a1 'd' a2) %nassoc 2; 63 | } 64 | 65 | class Literal: A { 66 | int val; 67 | syntax(val); 68 | } 69 | -------------------------------------------------------------------------------- /tests/prec1.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef prec1_INCLUDE_ 3 | #define prec1_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "prec1.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace prec1 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | class Bleft; 30 | class Bnassoc; 31 | class Bright; 32 | class Cleft; 33 | class Cnassoc; 34 | class Cright; 35 | class Dleft; 36 | class Dnassoc; 37 | class Dright; 38 | class Literal; 39 | /* END FORWARD DECLARATIONS */ 40 | 41 | // Base class for prec1 AST nodes 42 | class AstNode : public classp::ClasspNode { 43 | public: 44 | string className() override { return "AstNode"; } 45 | AstNode(ParseState parseState) 46 | : parseState(parseState) { 47 | } 48 | 49 | // Write out a bracketed form of this AST from the declared syntax. 50 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 51 | assert(false); 52 | } 53 | 54 | ParseState parseState; 55 | }; 56 | 57 | /* BEGIN CLASS DEFINITIONS */ 58 | class A: public AstNode { 59 | public: 60 | string className() override { return "A"; } 61 | A(ParseState parseState); 62 | void printMembers(ostream& out) override; 63 | void bracketFormat(ostream& out, AstNode* self) override; 64 | 65 | }; 66 | 67 | class Bleft: public A { 68 | public: 69 | string className() override { return "Bleft"; } 70 | Bleft(ParseState parseState, A* a); 71 | void printMembers(ostream& out) override; 72 | void format(ostream& out, int precedence) override; 73 | 74 | A* a = nullptr; 75 | }; 76 | 77 | class Cleft: public A { 78 | public: 79 | string className() override { return "Cleft"; } 80 | Cleft(ParseState parseState, A* a); 81 | void printMembers(ostream& out) override; 82 | void format(ostream& out, int precedence) override; 83 | 84 | A* a = nullptr; 85 | }; 86 | 87 | class Dleft: public A { 88 | public: 89 | string className() override { return "Dleft"; } 90 | Dleft(ParseState parseState, A* a1, A* a2); 91 | void printMembers(ostream& out) override; 92 | void format(ostream& out, int precedence) override; 93 | 94 | A* a1 = nullptr; 95 | A* a2 = nullptr; 96 | }; 97 | 98 | class Bright: public A { 99 | public: 100 | string className() override { return "Bright"; } 101 | Bright(ParseState parseState, A* a); 102 | void printMembers(ostream& out) override; 103 | void format(ostream& out, int precedence) override; 104 | 105 | A* a = nullptr; 106 | }; 107 | 108 | class Cright: public A { 109 | public: 110 | string className() override { return "Cright"; } 111 | Cright(ParseState parseState, A* a); 112 | void printMembers(ostream& out) override; 113 | void format(ostream& out, int precedence) override; 114 | 115 | A* a = nullptr; 116 | }; 117 | 118 | class Dright: public A { 119 | public: 120 | string className() override { return "Dright"; } 121 | Dright(ParseState parseState, A* a1, A* a2); 122 | void printMembers(ostream& out) override; 123 | void format(ostream& out, int precedence) override; 124 | 125 | A* a1 = nullptr; 126 | A* a2 = nullptr; 127 | }; 128 | 129 | class Bnassoc: public A { 130 | public: 131 | string className() override { return "Bnassoc"; } 132 | Bnassoc(ParseState parseState, A* a); 133 | void printMembers(ostream& out) override; 134 | void format(ostream& out, int precedence) override; 135 | 136 | A* a = nullptr; 137 | }; 138 | 139 | class Cnassoc: public A { 140 | public: 141 | string className() override { return "Cnassoc"; } 142 | Cnassoc(ParseState parseState, A* a); 143 | void printMembers(ostream& out) override; 144 | void format(ostream& out, int precedence) override; 145 | 146 | A* a = nullptr; 147 | }; 148 | 149 | class Dnassoc: public A { 150 | public: 151 | string className() override { return "Dnassoc"; } 152 | Dnassoc(ParseState parseState, A* a1, A* a2); 153 | void printMembers(ostream& out) override; 154 | void format(ostream& out, int precedence) override; 155 | 156 | A* a1 = nullptr; 157 | A* a2 = nullptr; 158 | }; 159 | 160 | class Literal: public A { 161 | public: 162 | string className() override { return "Literal"; } 163 | Literal(ParseState parseState, int val); 164 | void printMembers(ostream& out) override; 165 | void format(ostream& out, int precedence) override; 166 | 167 | int val; 168 | }; 169 | /* END CLASS DEFINITIONS */ 170 | 171 | } // namespace prec1 172 | #endif // prec1_INCLUDE_ 173 | 174 | /* END HEADER */ 175 | -------------------------------------------------------------------------------- /tests/prec2: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class Expression { 20 | %parseable; 21 | sample('4-1+2+3-5', '(Diff arg1:(Sum args:[(Diff arg1:(Base n:4) arg2:(Base n:1)), (Base n:2), (Base n:3)]) arg2:(Base n:5))'); 22 | } 23 | 24 | class Sum: Expression { 25 | Expression args[]; 26 | syntax(args+'+') %left 1; 27 | } 28 | 29 | class Diff: Expression { 30 | Expression arg1; 31 | Expression arg2; 32 | syntax(arg1 '-' arg2) %left 1; 33 | } 34 | 35 | class Base : Expression { 36 | int n; 37 | syntax(n); 38 | } 39 | -------------------------------------------------------------------------------- /tests/prec2.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef prec2_INCLUDE_ 3 | #define prec2_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "prec2.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace prec2 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class Base; 29 | class Diff; 30 | class Expression; 31 | class Sum; 32 | /* END FORWARD DECLARATIONS */ 33 | 34 | // Base class for prec2 AST nodes 35 | class AstNode : public classp::ClasspNode { 36 | public: 37 | string className() override { return "AstNode"; } 38 | AstNode(ParseState parseState) 39 | : parseState(parseState) { 40 | } 41 | 42 | // Write out a bracketed form of this AST from the declared syntax. 43 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 44 | assert(false); 45 | } 46 | 47 | ParseState parseState; 48 | }; 49 | 50 | /* BEGIN CLASS DEFINITIONS */ 51 | class Expression: public AstNode { 52 | public: 53 | string className() override { return "Expression"; } 54 | Expression(ParseState parseState); 55 | static Expression* parse(istream& input, ostream& errors); 56 | void printMembers(ostream& out) override; 57 | void bracketFormat(ostream& out, AstNode* self) override; 58 | 59 | }; 60 | 61 | class Sum: public Expression { 62 | public: 63 | string className() override { return "Sum"; } 64 | Sum(ParseState parseState, vector args); 65 | void printMembers(ostream& out) override; 66 | void format(ostream& out, int precedence) override; 67 | 68 | vector args; 69 | }; 70 | 71 | class Diff: public Expression { 72 | public: 73 | string className() override { return "Diff"; } 74 | Diff(ParseState parseState, Expression* arg1, Expression* arg2); 75 | void printMembers(ostream& out) override; 76 | void format(ostream& out, int precedence) override; 77 | 78 | Expression* arg1 = nullptr; 79 | Expression* arg2 = nullptr; 80 | }; 81 | 82 | class Base: public Expression { 83 | public: 84 | string className() override { return "Base"; } 85 | Base(ParseState parseState, int n); 86 | void printMembers(ostream& out) override; 87 | void format(ostream& out, int precedence) override; 88 | 89 | int n; 90 | }; 91 | /* END CLASS DEFINITIONS */ 92 | 93 | } // namespace prec2 94 | #endif // prec2_INCLUDE_ 95 | 96 | /* END HEADER */ 97 | -------------------------------------------------------------------------------- /tests/prec2.l: -------------------------------------------------------------------------------- 1 | /* BEGIN LEXER */ 2 | %{ 3 | 4 | #define prec2_LEX_CC_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "prec2.yacc.hh" 13 | 14 | namespace prec2 { 15 | 16 | class AstNode; 17 | 18 | // ParseDriver initiates a parse and contains the state data used during a 19 | // single parsing session (that is, during the parse of one file or string). 20 | class ParseDriver : public yyFlexLexer { 21 | public: 22 | ParseDriver(std::istream& source, std::ostream& errors); 23 | ~ParseDriver() override; 24 | 25 | // A function used by the lexer to report errors. 26 | void Error(const YYParser::location_type& loc, const std::string& msg); 27 | void Error(const std::string& msg); 28 | void Fatal(const YYParser::location_type& loc, const std::string& msg); 29 | void LexerError(const char* msg) override; 30 | void LexerError(const string& msg) { LexerError(msg.c_str()); } 31 | 32 | // Flex-generated function to get the next token from input 33 | virtual YYParser::symbol_type NextToken(ParseDriver* parser); 34 | 35 | // Unput a char and reset location. 36 | virtual void Unput(char c); 37 | 38 | void set_initial_token(YYParser::token_type token) { initial_token_ = token; } 39 | 40 | void consume_initial_token(YYParser::token_type* token) { 41 | *token = initial_token_; 42 | initial_token_ = YYParser::token::TOK_EOF; 43 | } 44 | 45 | int numErrors() { return num_errors_; } 46 | 47 | protected: 48 | const YYParser::location_type* location() { return &location_; } 49 | 50 | private: 51 | std::istream* source_; // Not owned. 52 | std::ostream& errors_; 53 | int num_errors_ = 0; 54 | YYParser::location_type location_; 55 | std::unique_ptr file_name_; 56 | YYParser::token_type initial_token_; 57 | std::stringstream current_token_; // a string token being built up 58 | 59 | // Disallow copy and assign. 60 | ParseDriver(const ParseDriver&) = delete; 61 | void operator=(const ParseDriver&) = delete; 62 | }; 63 | 64 | } // namespace prec2 65 | 66 | using prec2::YYParser; 67 | 68 | #undef YY_DECL 69 | #define YY_DECL \ 70 | YYParser::symbol_type prec2::ParseDriver::NextToken(prec2::ParseDriver* parser) 71 | 72 | typedef YYParser::token token; 73 | 74 | #define yylloc location_ 75 | #define yyterminate() return YYParser::make_TOK_EOF(yylloc) 76 | #define YY_USER_ACTION yylloc.columns(yyleng); 77 | 78 | %} 79 | 80 | %option 8bit 81 | %option batch 82 | %option c++ 83 | %option full 84 | %option noyywrap 85 | %option yyclass="prec2::ParseDriver" 86 | 87 | %x string_literal 88 | %x blank 89 | %x comment 90 | 91 | EOL \r\n|\n 92 | DDIGIT [[:digit:]] 93 | ALNUM [[:alnum:]_] 94 | ALPHA [[:alpha:]_] 95 | BLANK [[:blank:]\t] 96 | 97 | DDIGITS {DDIGIT}(_?{DDIGIT})* 98 | EXPONENT {EXP}{SIGN}?{DDIGITS} 99 | 100 | %% 101 | 102 | %{ 103 | yylloc.step(); 104 | %} 105 | 106 | false { 107 | return YYParser::make_TOK_BOOL(false, yylloc); 108 | } 109 | 110 | true { 111 | return YYParser::make_TOK_BOOL(true, yylloc); 112 | } 113 | 114 | /* BEGIN GENERATED TOKENS */ 115 | \+ { return YYParser::make_TOK_PLUS(yylloc); } 116 | \- { return YYParser::make_TOK_MINUS(yylloc); } 117 | /* END GENERATED TOKENS */ 118 | 119 | <> { 120 | return YYParser::make_TOK_EOF(yylloc); 121 | } 122 | 123 | ' { 124 | current_token_.str(""); 125 | BEGIN(string_literal); 126 | } 127 | 128 | \/\/ { 129 | BEGIN(comment); 130 | } 131 | 132 | { 133 | 134 | '' { 135 | current_token_ << '\''; 136 | } 137 | 138 | \' { 139 | BEGIN(INITIAL); 140 | return YYParser::make_TOK_STRING_LITERAL(current_token_.str(), yylloc); 141 | } 142 | 143 | {EOL} { 144 | BEGIN(INITIAL); 145 | yylloc.lines(1); 146 | LexerError("string not terminated: '" + current_token_.str() + "'"); 147 | } 148 | 149 | [[:cntrl:]] { 150 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 151 | } 152 | 153 | <> { 154 | BEGIN(INITIAL); 155 | LexerError("string not terminated: '" + current_token_.str() + "'"); 156 | } 157 | 158 | . { 159 | current_token_ << YYText(); 160 | } 161 | } 162 | 163 | { 164 | {EOL} { 165 | BEGIN(INITIAL); 166 | Unput('\n'); 167 | } 168 | } 169 | 170 | {BLANK}+ { 171 | } 172 | 173 | /* integer literal */ 174 | {DDIGITS} { 175 | return YYParser::make_TOK_INT64(strtol(YYText(), nullptr, 10), yylloc); 176 | } 177 | 178 | /* identifier */ 179 | {ALPHA}(-*{ALNUM})* { 180 | return YYParser::make_TOK_IDENTIFIER(YYText(), yylloc); 181 | } 182 | 183 | /* Any other character. */ 184 | . { 185 | if (isprint(YYText()[0])) { 186 | LexerError(string("unexpected character: '") + YYText() + "'"); 187 | } else { 188 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 189 | } 190 | } 191 | 192 | %% 193 | 194 | namespace prec2 { 195 | 196 | using std::istream; 197 | using std::ostream; 198 | 199 | class FatalParseError {}; 200 | 201 | AstNode* parse(istream& input, ostream& errors) { 202 | ParseDriver parser(input, errors); 203 | AstNode* result = nullptr; 204 | YYParser yyparser(&parser, &result); 205 | int ret_val = 1; 206 | try { ret_val = yyparser.parse(); } 207 | catch (FatalParseError) {} 208 | if (ret_val || parser.numErrors() > 0) { 209 | errors << parser.numErrors() << " errors.\n"; 210 | return nullptr; 211 | } 212 | return result; 213 | } 214 | 215 | YYParser::symbol_type yylex(ParseDriver* parser) { 216 | return parser->NextToken(parser); 217 | } 218 | 219 | void YYParser::error(const location_type& loc, const std::string& msg) { 220 | parser->Error(loc, msg); 221 | } 222 | 223 | ParseDriver::ParseDriver(std::istream& source, std::ostream& errors) 224 | : yyFlexLexer(&source) 225 | , source_(&source) 226 | , errors_(errors) 227 | , initial_token_(YYParser::token::TOK_EOF) {} 228 | 229 | ParseDriver::~ParseDriver() { 230 | // This should be done by the parent, but it uses delete, not delete[]... 231 | delete[] yy_state_buf; 232 | yy_state_buf = NULL; 233 | 234 | if (yy_start_stack != NULL) { 235 | free(yy_start_stack); 236 | yy_start_stack = NULL; 237 | } 238 | } 239 | 240 | void ParseDriver::Error( 241 | const YYParser::location_type& loc, const std::string& msg) { 242 | errors_ << "ERROR: " << loc << ":" << msg << std::endl; 243 | num_errors_++; 244 | } 245 | 246 | void ParseDriver::Error(const std::string& msg) { 247 | errors_ << "ERROR: " << msg << std::endl; 248 | num_errors_++; 249 | } 250 | 251 | void ParseDriver::Fatal( 252 | const YYParser::location_type& loc, const std::string& msg) { 253 | Error(loc, msg); 254 | throw FatalParseError(); 255 | } 256 | 257 | void ParseDriver::LexerError(const char* msg) { 258 | Fatal(location_, msg); 259 | } 260 | 261 | void ParseDriver::Unput(char c) { 262 | assert(location_.end.column > 0); 263 | location_.end.column--; 264 | yyunput(c, yytext); 265 | } 266 | 267 | } // namespace prec2 268 | /* END LEXER */ 269 | -------------------------------------------------------------------------------- /tests/prec3: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class Expression { 20 | %parseable; 21 | sample('4-1+2-5', print); 22 | sample('4-1+2+3-5', print); 23 | sample('4-1*2-5', print); 24 | sample('4-1*2*3-5', print); 25 | sample('4*1+2+3*5', print); 26 | sample('4+1*2*3+5', print); 27 | sample('1*2-3*4*5/6*7*8', print); 28 | } 29 | 30 | class Sum: Expression { 31 | Expression args[]; 32 | syntax(args+'+') %left 1; 33 | } 34 | 35 | class Diff: Expression { 36 | Expression arg1; 37 | Expression arg2; 38 | syntax(arg1 '-' arg2) %left 1; 39 | } 40 | 41 | class Prod: Expression { 42 | Expression args[]; 43 | syntax(args+'*') %left 1; 44 | } 45 | 46 | class Div: Expression { 47 | Expression arg1; 48 | Expression arg2; 49 | syntax(arg1 '/' arg2) %left 2; 50 | } 51 | 52 | class Base : Expression { 53 | int n; 54 | syntax(n); 55 | } 56 | -------------------------------------------------------------------------------- /tests/prec4: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class Expression { 20 | %parseable; 21 | sample('a', '(IntegerLiteral)'); 22 | sample('a+a*a', '(Sum val1:(IntegerLiteral) val2:(Product val1:(IntegerLiteral) val2:(IntegerLiteral)))'); 23 | } 24 | 25 | class Sum: Expression { 26 | Expression val1; 27 | Expression val2; 28 | syntax (val1 '+' val2) %left 1; 29 | } 30 | 31 | class Product: Expression { 32 | Expression val1; 33 | Expression val2; 34 | syntax (val1 '*' val2) %left 2; 35 | } 36 | 37 | class IntegerLiteral: Expression { 38 | syntax ( 'a' ) %left 3; 39 | } 40 | -------------------------------------------------------------------------------- /tests/prec4.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef prec4_INCLUDE_ 3 | #define prec4_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "prec4.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace prec4 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class Expression; 29 | class IntegerLiteral; 30 | class Product; 31 | class Sum; 32 | /* END FORWARD DECLARATIONS */ 33 | 34 | // Base class for prec4 AST nodes 35 | class AstNode : public classp::ClasspNode { 36 | public: 37 | string className() override { return "AstNode"; } 38 | AstNode(ParseState parseState) 39 | : parseState(parseState) { 40 | } 41 | 42 | // Write out a bracketed form of this AST from the declared syntax. 43 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 44 | assert(false); 45 | } 46 | 47 | ParseState parseState; 48 | }; 49 | 50 | /* BEGIN CLASS DEFINITIONS */ 51 | class Expression: public AstNode { 52 | public: 53 | string className() override { return "Expression"; } 54 | Expression(ParseState parseState); 55 | static Expression* parse(istream& input, ostream& errors); 56 | void printMembers(ostream& out) override; 57 | void bracketFormat(ostream& out, AstNode* self) override; 58 | 59 | }; 60 | 61 | class Sum: public Expression { 62 | public: 63 | string className() override { return "Sum"; } 64 | Sum(ParseState parseState, Expression* val1, Expression* val2); 65 | void printMembers(ostream& out) override; 66 | void format(ostream& out, int precedence) override; 67 | 68 | Expression* val1 = nullptr; 69 | Expression* val2 = nullptr; 70 | }; 71 | 72 | class Product: public Expression { 73 | public: 74 | string className() override { return "Product"; } 75 | Product(ParseState parseState, Expression* val1, Expression* val2); 76 | void printMembers(ostream& out) override; 77 | void format(ostream& out, int precedence) override; 78 | 79 | Expression* val1 = nullptr; 80 | Expression* val2 = nullptr; 81 | }; 82 | 83 | class IntegerLiteral: public Expression { 84 | public: 85 | string className() override { return "IntegerLiteral"; } 86 | IntegerLiteral(ParseState parseState); 87 | void printMembers(ostream& out) override; 88 | void format(ostream& out, int precedence) override; 89 | 90 | }; 91 | /* END CLASS DEFINITIONS */ 92 | 93 | } // namespace prec4 94 | #endif // prec4_INCLUDE_ 95 | 96 | /* END HEADER */ 97 | -------------------------------------------------------------------------------- /tests/prec4.l: -------------------------------------------------------------------------------- 1 | /* BEGIN LEXER */ 2 | %{ 3 | 4 | #define prec4_LEX_CC_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "prec4.yacc.hh" 13 | 14 | namespace prec4 { 15 | 16 | class AstNode; 17 | 18 | // ParseDriver initiates a parse and contains the state data used during a 19 | // single parsing session (that is, during the parse of one file or string). 20 | class ParseDriver : public yyFlexLexer { 21 | public: 22 | ParseDriver(std::istream& source, std::ostream& errors); 23 | ~ParseDriver() override; 24 | 25 | // A function used by the lexer to report errors. 26 | void Error(const YYParser::location_type& loc, const std::string& msg); 27 | void Error(const std::string& msg); 28 | void Fatal(const YYParser::location_type& loc, const std::string& msg); 29 | void LexerError(const char* msg) override; 30 | void LexerError(const string& msg) { LexerError(msg.c_str()); } 31 | 32 | // Flex-generated function to get the next token from input 33 | virtual YYParser::symbol_type NextToken(ParseDriver* parser); 34 | 35 | // Unput a char and reset location. 36 | virtual void Unput(char c); 37 | 38 | void set_initial_token(YYParser::token_type token) { initial_token_ = token; } 39 | 40 | void consume_initial_token(YYParser::token_type* token) { 41 | *token = initial_token_; 42 | initial_token_ = YYParser::token::TOK_EOF; 43 | } 44 | 45 | int numErrors() { return num_errors_; } 46 | 47 | protected: 48 | const YYParser::location_type* location() { return &location_; } 49 | 50 | private: 51 | std::istream* source_; // Not owned. 52 | std::ostream& errors_; 53 | int num_errors_ = 0; 54 | YYParser::location_type location_; 55 | std::unique_ptr file_name_; 56 | YYParser::token_type initial_token_; 57 | std::stringstream current_token_; // a string token being built up 58 | 59 | // Disallow copy and assign. 60 | ParseDriver(const ParseDriver&) = delete; 61 | void operator=(const ParseDriver&) = delete; 62 | }; 63 | 64 | } // namespace prec4 65 | 66 | using prec4::YYParser; 67 | 68 | #undef YY_DECL 69 | #define YY_DECL \ 70 | YYParser::symbol_type prec4::ParseDriver::NextToken(prec4::ParseDriver* parser) 71 | 72 | typedef YYParser::token token; 73 | 74 | #define yylloc location_ 75 | #define yyterminate() return YYParser::make_TOK_EOF(yylloc) 76 | #define YY_USER_ACTION yylloc.columns(yyleng); 77 | 78 | %} 79 | 80 | %option 8bit 81 | %option batch 82 | %option c++ 83 | %option full 84 | %option noyywrap 85 | %option yyclass="prec4::ParseDriver" 86 | 87 | %x string_literal 88 | %x blank 89 | %x comment 90 | 91 | EOL \r\n|\n 92 | DDIGIT [[:digit:]] 93 | ALNUM [[:alnum:]_] 94 | ALPHA [[:alpha:]_] 95 | BLANK [[:blank:]\t] 96 | 97 | DDIGITS {DDIGIT}(_?{DDIGIT})* 98 | EXPONENT {EXP}{SIGN}?{DDIGITS} 99 | 100 | %% 101 | 102 | %{ 103 | yylloc.step(); 104 | %} 105 | 106 | false { 107 | return YYParser::make_TOK_BOOL(false, yylloc); 108 | } 109 | 110 | true { 111 | return YYParser::make_TOK_BOOL(true, yylloc); 112 | } 113 | 114 | /* BEGIN GENERATED TOKENS */ 115 | \* { return YYParser::make_TOK_STAR(yylloc); } 116 | \+ { return YYParser::make_TOK_PLUS(yylloc); } 117 | a { return YYParser::make_WORD_a(yylloc); } 118 | /* END GENERATED TOKENS */ 119 | 120 | <> { 121 | return YYParser::make_TOK_EOF(yylloc); 122 | } 123 | 124 | ' { 125 | current_token_.str(""); 126 | BEGIN(string_literal); 127 | } 128 | 129 | \/\/ { 130 | BEGIN(comment); 131 | } 132 | 133 | { 134 | 135 | '' { 136 | current_token_ << '\''; 137 | } 138 | 139 | \' { 140 | BEGIN(INITIAL); 141 | return YYParser::make_TOK_STRING_LITERAL(current_token_.str(), yylloc); 142 | } 143 | 144 | {EOL} { 145 | BEGIN(INITIAL); 146 | yylloc.lines(1); 147 | LexerError("string not terminated: '" + current_token_.str() + "'"); 148 | } 149 | 150 | [[:cntrl:]] { 151 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 152 | } 153 | 154 | <> { 155 | BEGIN(INITIAL); 156 | LexerError("string not terminated: '" + current_token_.str() + "'"); 157 | } 158 | 159 | . { 160 | current_token_ << YYText(); 161 | } 162 | } 163 | 164 | { 165 | {EOL} { 166 | BEGIN(INITIAL); 167 | Unput('\n'); 168 | } 169 | } 170 | 171 | {BLANK}+ { 172 | } 173 | 174 | /* integer literal */ 175 | {DDIGITS} { 176 | return YYParser::make_TOK_INT64(strtol(YYText(), nullptr, 10), yylloc); 177 | } 178 | 179 | /* identifier */ 180 | {ALPHA}(-*{ALNUM})* { 181 | return YYParser::make_TOK_IDENTIFIER(YYText(), yylloc); 182 | } 183 | 184 | /* Any other character. */ 185 | . { 186 | if (isprint(YYText()[0])) { 187 | LexerError(string("unexpected character: '") + YYText() + "'"); 188 | } else { 189 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 190 | } 191 | } 192 | 193 | %% 194 | 195 | namespace prec4 { 196 | 197 | using std::istream; 198 | using std::ostream; 199 | 200 | class FatalParseError {}; 201 | 202 | AstNode* parse(istream& input, ostream& errors) { 203 | ParseDriver parser(input, errors); 204 | AstNode* result = nullptr; 205 | YYParser yyparser(&parser, &result); 206 | int ret_val = 1; 207 | try { ret_val = yyparser.parse(); } 208 | catch (FatalParseError) {} 209 | if (ret_val || parser.numErrors() > 0) { 210 | errors << parser.numErrors() << " errors.\n"; 211 | return nullptr; 212 | } 213 | return result; 214 | } 215 | 216 | YYParser::symbol_type yylex(ParseDriver* parser) { 217 | return parser->NextToken(parser); 218 | } 219 | 220 | void YYParser::error(const location_type& loc, const std::string& msg) { 221 | parser->Error(loc, msg); 222 | } 223 | 224 | ParseDriver::ParseDriver(std::istream& source, std::ostream& errors) 225 | : yyFlexLexer(&source) 226 | , source_(&source) 227 | , errors_(errors) 228 | , initial_token_(YYParser::token::TOK_EOF) {} 229 | 230 | ParseDriver::~ParseDriver() { 231 | // This should be done by the parent, but it uses delete, not delete[]... 232 | delete[] yy_state_buf; 233 | yy_state_buf = NULL; 234 | 235 | if (yy_start_stack != NULL) { 236 | free(yy_start_stack); 237 | yy_start_stack = NULL; 238 | } 239 | } 240 | 241 | void ParseDriver::Error( 242 | const YYParser::location_type& loc, const std::string& msg) { 243 | errors_ << "ERROR: " << loc << ":" << msg << std::endl; 244 | num_errors_++; 245 | } 246 | 247 | void ParseDriver::Error(const std::string& msg) { 248 | errors_ << "ERROR: " << msg << std::endl; 249 | num_errors_++; 250 | } 251 | 252 | void ParseDriver::Fatal( 253 | const YYParser::location_type& loc, const std::string& msg) { 254 | Error(loc, msg); 255 | throw FatalParseError(); 256 | } 257 | 258 | void ParseDriver::LexerError(const char* msg) { 259 | Fatal(location_, msg); 260 | } 261 | 262 | void ParseDriver::Unput(char c) { 263 | assert(location_.end.column > 0); 264 | location_.end.column--; 265 | yyunput(c, yytext); 266 | } 267 | 268 | } // namespace prec4 269 | /* END LEXER */ 270 | -------------------------------------------------------------------------------- /tests/samples: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | // This is a test for the samples feature, not for parsing. 20 | class A { 21 | %parseable; 22 | int n; 23 | syntax('+' n); 24 | sample('+ 1'); 25 | sample('+ 2', succeed); 26 | sample('+ 3', fail); 27 | sample('+ 4', print); 28 | sample('+ 5', '(A n:5)'); 29 | sample('+ 6', 'testing'); 30 | sample('@ 7'); 31 | sample('- 8', succeed); 32 | sample('- 9', fail); 33 | sample('- 10', print); 34 | sample('- 11', 'testing'); 35 | } 36 | -------------------------------------------------------------------------------- /tests/samples.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef samples_INCLUDE_ 3 | #define samples_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "samples.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace samples { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | /* END FORWARD DECLARATIONS */ 30 | 31 | // Base class for samples AST nodes 32 | class AstNode : public classp::ClasspNode { 33 | public: 34 | string className() override { return "AstNode"; } 35 | AstNode(ParseState parseState) 36 | : parseState(parseState) { 37 | } 38 | 39 | // Write out a bracketed form of this AST from the declared syntax. 40 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 41 | assert(false); 42 | } 43 | 44 | ParseState parseState; 45 | }; 46 | 47 | /* BEGIN CLASS DEFINITIONS */ 48 | class A: public AstNode { 49 | public: 50 | string className() override { return "A"; } 51 | A(ParseState parseState, int n); 52 | static A* parse(istream& input, ostream& errors); 53 | void printMembers(ostream& out) override; 54 | void format(ostream& out, int precedence) override; 55 | 56 | int n; 57 | }; 58 | /* END CLASS DEFINITIONS */ 59 | 60 | } // namespace samples 61 | #endif // samples_INCLUDE_ 62 | 63 | /* END HEADER */ 64 | -------------------------------------------------------------------------------- /tests/samples.l: -------------------------------------------------------------------------------- 1 | /* BEGIN LEXER */ 2 | %{ 3 | 4 | #define samples_LEX_CC_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "samples.yacc.hh" 13 | 14 | namespace samples { 15 | 16 | class AstNode; 17 | 18 | // ParseDriver initiates a parse and contains the state data used during a 19 | // single parsing session (that is, during the parse of one file or string). 20 | class ParseDriver : public yyFlexLexer { 21 | public: 22 | ParseDriver(std::istream& source, std::ostream& errors); 23 | ~ParseDriver() override; 24 | 25 | // A function used by the lexer to report errors. 26 | void Error(const YYParser::location_type& loc, const std::string& msg); 27 | void Error(const std::string& msg); 28 | void Fatal(const YYParser::location_type& loc, const std::string& msg); 29 | void LexerError(const char* msg) override; 30 | void LexerError(const string& msg) { LexerError(msg.c_str()); } 31 | 32 | // Flex-generated function to get the next token from input 33 | virtual YYParser::symbol_type NextToken(ParseDriver* parser); 34 | 35 | // Unput a char and reset location. 36 | virtual void Unput(char c); 37 | 38 | void set_initial_token(YYParser::token_type token) { initial_token_ = token; } 39 | 40 | void consume_initial_token(YYParser::token_type* token) { 41 | *token = initial_token_; 42 | initial_token_ = YYParser::token::TOK_EOF; 43 | } 44 | 45 | int numErrors() { return num_errors_; } 46 | 47 | protected: 48 | const YYParser::location_type* location() { return &location_; } 49 | 50 | private: 51 | std::istream* source_; // Not owned. 52 | std::ostream& errors_; 53 | int num_errors_ = 0; 54 | YYParser::location_type location_; 55 | std::unique_ptr file_name_; 56 | YYParser::token_type initial_token_; 57 | std::stringstream current_token_; // a string token being built up 58 | 59 | // Disallow copy and assign. 60 | ParseDriver(const ParseDriver&) = delete; 61 | void operator=(const ParseDriver&) = delete; 62 | }; 63 | 64 | } // namespace samples 65 | 66 | using samples::YYParser; 67 | 68 | #undef YY_DECL 69 | #define YY_DECL \ 70 | YYParser::symbol_type samples::ParseDriver::NextToken(samples::ParseDriver* parser) 71 | 72 | typedef YYParser::token token; 73 | 74 | #define yylloc location_ 75 | #define yyterminate() return YYParser::make_TOK_EOF(yylloc) 76 | #define YY_USER_ACTION yylloc.columns(yyleng); 77 | 78 | %} 79 | 80 | %option 8bit 81 | %option batch 82 | %option c++ 83 | %option full 84 | %option noyywrap 85 | %option yyclass="samples::ParseDriver" 86 | 87 | %x string_literal 88 | %x blank 89 | %x comment 90 | 91 | EOL \r\n|\n 92 | DDIGIT [[:digit:]] 93 | ALNUM [[:alnum:]_] 94 | ALPHA [[:alpha:]_] 95 | BLANK [[:blank:]\t] 96 | 97 | DDIGITS {DDIGIT}(_?{DDIGIT})* 98 | EXPONENT {EXP}{SIGN}?{DDIGITS} 99 | 100 | %% 101 | 102 | %{ 103 | yylloc.step(); 104 | %} 105 | 106 | false { 107 | return YYParser::make_TOK_BOOL(false, yylloc); 108 | } 109 | 110 | true { 111 | return YYParser::make_TOK_BOOL(true, yylloc); 112 | } 113 | 114 | /* BEGIN GENERATED TOKENS */ 115 | \+ { return YYParser::make_TOK_PLUS(yylloc); } 116 | /* END GENERATED TOKENS */ 117 | 118 | <> { 119 | return YYParser::make_TOK_EOF(yylloc); 120 | } 121 | 122 | ' { 123 | current_token_.str(""); 124 | BEGIN(string_literal); 125 | } 126 | 127 | \/\/ { 128 | BEGIN(comment); 129 | } 130 | 131 | { 132 | 133 | '' { 134 | current_token_ << '\''; 135 | } 136 | 137 | \' { 138 | BEGIN(INITIAL); 139 | return YYParser::make_TOK_STRING_LITERAL(current_token_.str(), yylloc); 140 | } 141 | 142 | {EOL} { 143 | BEGIN(INITIAL); 144 | yylloc.lines(1); 145 | LexerError("string not terminated: '" + current_token_.str() + "'"); 146 | } 147 | 148 | [[:cntrl:]] { 149 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 150 | } 151 | 152 | <> { 153 | BEGIN(INITIAL); 154 | LexerError("string not terminated: '" + current_token_.str() + "'"); 155 | } 156 | 157 | . { 158 | current_token_ << YYText(); 159 | } 160 | } 161 | 162 | { 163 | {EOL} { 164 | BEGIN(INITIAL); 165 | Unput('\n'); 166 | } 167 | } 168 | 169 | {BLANK}+ { 170 | } 171 | 172 | /* integer literal */ 173 | {DDIGITS} { 174 | return YYParser::make_TOK_INT64(strtol(YYText(), nullptr, 10), yylloc); 175 | } 176 | 177 | /* identifier */ 178 | {ALPHA}(-*{ALNUM})* { 179 | return YYParser::make_TOK_IDENTIFIER(YYText(), yylloc); 180 | } 181 | 182 | /* Any other character. */ 183 | . { 184 | if (isprint(YYText()[0])) { 185 | LexerError(string("unexpected character: '") + YYText() + "'"); 186 | } else { 187 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 188 | } 189 | } 190 | 191 | %% 192 | 193 | namespace samples { 194 | 195 | using std::istream; 196 | using std::ostream; 197 | 198 | class FatalParseError {}; 199 | 200 | AstNode* parse(istream& input, ostream& errors) { 201 | ParseDriver parser(input, errors); 202 | AstNode* result = nullptr; 203 | YYParser yyparser(&parser, &result); 204 | int ret_val = 1; 205 | try { ret_val = yyparser.parse(); } 206 | catch (FatalParseError) {} 207 | if (ret_val || parser.numErrors() > 0) { 208 | errors << parser.numErrors() << " errors.\n"; 209 | return nullptr; 210 | } 211 | return result; 212 | } 213 | 214 | YYParser::symbol_type yylex(ParseDriver* parser) { 215 | return parser->NextToken(parser); 216 | } 217 | 218 | void YYParser::error(const location_type& loc, const std::string& msg) { 219 | parser->Error(loc, msg); 220 | } 221 | 222 | ParseDriver::ParseDriver(std::istream& source, std::ostream& errors) 223 | : yyFlexLexer(&source) 224 | , source_(&source) 225 | , errors_(errors) 226 | , initial_token_(YYParser::token::TOK_EOF) {} 227 | 228 | ParseDriver::~ParseDriver() { 229 | // This should be done by the parent, but it uses delete, not delete[]... 230 | delete[] yy_state_buf; 231 | yy_state_buf = NULL; 232 | 233 | if (yy_start_stack != NULL) { 234 | free(yy_start_stack); 235 | yy_start_stack = NULL; 236 | } 237 | } 238 | 239 | void ParseDriver::Error( 240 | const YYParser::location_type& loc, const std::string& msg) { 241 | errors_ << "ERROR: " << loc << ":" << msg << std::endl; 242 | num_errors_++; 243 | } 244 | 245 | void ParseDriver::Error(const std::string& msg) { 246 | errors_ << "ERROR: " << msg << std::endl; 247 | num_errors_++; 248 | } 249 | 250 | void ParseDriver::Fatal( 251 | const YYParser::location_type& loc, const std::string& msg) { 252 | Error(loc, msg); 253 | throw FatalParseError(); 254 | } 255 | 256 | void ParseDriver::LexerError(const char* msg) { 257 | Fatal(location_, msg); 258 | } 259 | 260 | void ParseDriver::Unput(char c) { 261 | assert(location_.end.column > 0); 262 | location_.end.column--; 263 | yyunput(c, yytext); 264 | } 265 | 266 | } // namespace samples 267 | /* END LEXER */ 268 | -------------------------------------------------------------------------------- /tests/samples.out: -------------------------------------------------------------------------------- 1 | parsing sample '+ 1': 2 | parsing formatted result '+ 1' 3 | SUCCEEDS 4 | parsing sample '+ 2': 5 | parsing formatted result '+ 2' 6 | SUCCEEDS 7 | parsing sample '+ 3': 8 | ERROR[succeeds but expected fail: 9 | result->(A n:3)] 10 | parsing sample '+ 4': 11 | parsing formatted result '+ 4' 12 | SUCCEEDS: (A n:4) 13 | parsing sample '+ 5': 14 | parsing formatted result '+ 5' 15 | SUCCEEDS 16 | parsing sample '+ 6': 17 | parsing formatted result '+ 6' 18 | SUCCEEDS 19 | ERROR[expected and actual result do not match: 20 | expected-> testing 21 | actual-> (A n:6) 22 | ] 23 | parsing sample '@ 7': 24 | FAILS: ERROR[expected success] 25 | ERROR: 1.1:unexpected character: '@' 26 | 1 errors. 27 | parsing sample '- 8': 28 | FAILS: ERROR[expected success] 29 | ERROR: 1.1:unexpected character: '-' 30 | 1 errors. 31 | parsing sample '- 9': 32 | FAILS [as expected] 33 | parsing sample '- 10': 34 | FAILS: ERROR[expected success] 35 | ERROR: 1.1:unexpected character: '-' 36 | 1 errors. 37 | parsing sample '- 11': 38 | FAILS: ERROR[expected testing] 39 | ERROR: 1.1:unexpected character: '-' 40 | 1 errors. 41 | Errors: 6 42 | -------------------------------------------------------------------------------- /tests/sql1: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class SelectClause { 20 | // Each attribute can be given its own syntax. This is the same as putting the 21 | // syntax into the main syntax for the clause, except that self is interpreted 22 | // to refer to the attribute. 23 | bool distinct=false syntax(self{'DISTINCT'->true|}); 24 | Expression projections[]; 25 | Tag projectionTags[]; 26 | TableExpression from[] syntax('FROM' (self + ',')|); 27 | optional Expression where syntax (WHERE self|); 28 | Expression group_by[] syntax ('GROUP BY' (self + ',')|); 29 | optional Expression having syntax ('HAVING' self|); 30 | OrderByList order_by order_expr[] syntax ('ORDER BY' (self + ',')|); 31 | 32 | syntax ( 33 | 'SELECT' distinct (projections projectionTags + ',') 34 | from where group_by having order_by); 35 | }; 36 | 37 | class Tag { 38 | optional identifier id = ''; 39 | syntax(tag|); 40 | } 41 | 42 | class Expression { 43 | identifier id; 44 | syntax(id); 45 | } 46 | 47 | class TableExpression {} 48 | 49 | class BaseTableExpr extends TableExpression { 50 | Identifier name; 51 | } 52 | 53 | class JoinExpression extends TableExpression { 54 | TableExpression table1; 55 | TableExpression table2; 56 | optional Expression on syntax('ON' self); 57 | optional identifier usingList syntax('USING' (self + ',')); 58 | } 59 | 60 | class CrossJoinExpression extends JoinExpression { 61 | syntax %left 5 (table1 CROSS[ JOIN] table2); 62 | } 63 | 64 | class InnerJoinExpression extends JoinExpression { 65 | syntax %left 5 66 | (table1 (INNER|) JOIN table2 (on|using)); 67 | } 68 | 69 | enum OuterJoinType {left, right, full}; 70 | 71 | class OuterJoinExpression extends JoinExpression { 72 | OuterJoinType join_type 73 | syntax(self{'LEFT'->left | 'RIGHT'->right | 'FULL'->full | ->left}); 74 | Syntax %left 5 (table1 join_type ('OUTER'|) 'JOIN' table2 (on|using)); 75 | } 76 | -------------------------------------------------------------------------------- /tests/t1: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class A { 20 | optional int x; 21 | } 22 | class B: A { 23 | optional int y; 24 | syntax ('x' x 'y' y); 25 | } 26 | class C: A { 27 | optional int z; 28 | syntax ('x' x 'z' z); 29 | } 30 | class D { 31 | A a; 32 | B b; 33 | C c; 34 | syntax ('a' a 'b' b 'c' c); 35 | %parseable; 36 | sample ('a x 2 y 3 b x 4 y 5 c x 6 z 7', print); 37 | } 38 | -------------------------------------------------------------------------------- /tests/t1.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t1_INCLUDE_ 3 | #define t1_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t1.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t1 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | class B; 30 | class C; 31 | class D; 32 | /* END FORWARD DECLARATIONS */ 33 | 34 | // Base class for t1 AST nodes 35 | class AstNode : public classp::ClasspNode { 36 | public: 37 | string className() override { return "AstNode"; } 38 | AstNode(ParseState parseState) 39 | : parseState(parseState) { 40 | } 41 | 42 | // Write out a bracketed form of this AST from the declared syntax. 43 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 44 | assert(false); 45 | } 46 | 47 | ParseState parseState; 48 | }; 49 | 50 | /* BEGIN CLASS DEFINITIONS */ 51 | class A: public AstNode { 52 | public: 53 | string className() override { return "A"; } 54 | A(ParseState parseState, AttributeMap& keyword_args); 55 | void printMembers(ostream& out) override; 56 | 57 | int x; 58 | bool has_x = false; 59 | }; 60 | 61 | class B: public A { 62 | public: 63 | string className() override { return "B"; } 64 | B(ParseState parseState, AttributeMap& keyword_args); 65 | void printMembers(ostream& out) override; 66 | void format(ostream& out, int precedence) override; 67 | 68 | int y; 69 | bool has_y = false; 70 | }; 71 | 72 | class C: public A { 73 | public: 74 | string className() override { return "C"; } 75 | C(ParseState parseState, AttributeMap& keyword_args); 76 | void printMembers(ostream& out) override; 77 | void format(ostream& out, int precedence) override; 78 | 79 | int z; 80 | bool has_z = false; 81 | }; 82 | 83 | class D: public AstNode { 84 | public: 85 | string className() override { return "D"; } 86 | D(ParseState parseState, A* a, B* b, C* c); 87 | static D* parse(istream& input, ostream& errors); 88 | void printMembers(ostream& out) override; 89 | void format(ostream& out, int precedence) override; 90 | 91 | A* a = nullptr; 92 | B* b = nullptr; 93 | C* c = nullptr; 94 | }; 95 | /* END CLASS DEFINITIONS */ 96 | 97 | } // namespace t1 98 | #endif // t1_INCLUDE_ 99 | 100 | /* END HEADER */ 101 | -------------------------------------------------------------------------------- /tests/t10: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class Pattern { 20 | %parseable; 21 | syntax('(' self ')'); 22 | } 23 | 24 | class Iterator: Pattern { 25 | Pattern pattern1; 26 | Symbol separator; 27 | syntax(pattern1 '*' separator) %nassoc 2; 28 | } 29 | 30 | class Symbol : Pattern { 31 | identifier a; 32 | syntax(a); 33 | } 34 | -------------------------------------------------------------------------------- /tests/t10.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t10_INCLUDE_ 3 | #define t10_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t10.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t10 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class Iterator; 29 | class Pattern; 30 | class Symbol; 31 | /* END FORWARD DECLARATIONS */ 32 | 33 | // Base class for t10 AST nodes 34 | class AstNode : public classp::ClasspNode { 35 | public: 36 | string className() override { return "AstNode"; } 37 | AstNode(ParseState parseState) 38 | : parseState(parseState) { 39 | } 40 | 41 | // Write out a bracketed form of this AST from the declared syntax. 42 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 43 | assert(false); 44 | } 45 | 46 | ParseState parseState; 47 | }; 48 | 49 | /* BEGIN CLASS DEFINITIONS */ 50 | class Pattern: public AstNode { 51 | public: 52 | string className() override { return "Pattern"; } 53 | Pattern(ParseState parseState); 54 | static Pattern* parse(istream& input, ostream& errors); 55 | void printMembers(ostream& out) override; 56 | void bracketFormat(ostream& out, AstNode* self) override; 57 | 58 | }; 59 | 60 | class Iterator: public Pattern { 61 | public: 62 | string className() override { return "Iterator"; } 63 | Iterator(ParseState parseState, Pattern* pattern1, Symbol* separator); 64 | void printMembers(ostream& out) override; 65 | void format(ostream& out, int precedence) override; 66 | 67 | Pattern* pattern1 = nullptr; 68 | Symbol* separator = nullptr; 69 | }; 70 | 71 | class Symbol: public Pattern { 72 | public: 73 | string className() override { return "Symbol"; } 74 | Symbol(ParseState parseState, identifier a); 75 | void printMembers(ostream& out) override; 76 | void format(ostream& out, int precedence) override; 77 | 78 | identifier a; 79 | }; 80 | /* END CLASS DEFINITIONS */ 81 | 82 | } // namespace t10 83 | #endif // t10_INCLUDE_ 84 | 85 | /* END HEADER */ 86 | -------------------------------------------------------------------------------- /tests/t10.l: -------------------------------------------------------------------------------- 1 | /* BEGIN LEXER */ 2 | %{ 3 | 4 | #define t10_LEX_CC_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "t10.yacc.hh" 13 | 14 | namespace t10 { 15 | 16 | class AstNode; 17 | 18 | // ParseDriver initiates a parse and contains the state data used during a 19 | // single parsing session (that is, during the parse of one file or string). 20 | class ParseDriver : public yyFlexLexer { 21 | public: 22 | ParseDriver(std::istream& source, std::ostream& errors); 23 | ~ParseDriver() override; 24 | 25 | // A function used by the lexer to report errors. 26 | void Error(const YYParser::location_type& loc, const std::string& msg); 27 | void Error(const std::string& msg); 28 | void Fatal(const YYParser::location_type& loc, const std::string& msg); 29 | void LexerError(const char* msg) override; 30 | void LexerError(const string& msg) { LexerError(msg.c_str()); } 31 | 32 | // Flex-generated function to get the next token from input 33 | virtual YYParser::symbol_type NextToken(ParseDriver* parser); 34 | 35 | // Unput a char and reset location. 36 | virtual void Unput(char c); 37 | 38 | void set_initial_token(YYParser::token_type token) { initial_token_ = token; } 39 | 40 | void consume_initial_token(YYParser::token_type* token) { 41 | *token = initial_token_; 42 | initial_token_ = YYParser::token::TOK_EOF; 43 | } 44 | 45 | int numErrors() { return num_errors_; } 46 | 47 | protected: 48 | const YYParser::location_type* location() { return &location_; } 49 | 50 | private: 51 | std::istream* source_; // Not owned. 52 | std::ostream& errors_; 53 | int num_errors_ = 0; 54 | YYParser::location_type location_; 55 | std::unique_ptr file_name_; 56 | YYParser::token_type initial_token_; 57 | std::stringstream current_token_; // a string token being built up 58 | 59 | // Disallow copy and assign. 60 | ParseDriver(const ParseDriver&) = delete; 61 | void operator=(const ParseDriver&) = delete; 62 | }; 63 | 64 | } // namespace t10 65 | 66 | using t10::YYParser; 67 | 68 | #undef YY_DECL 69 | #define YY_DECL \ 70 | YYParser::symbol_type t10::ParseDriver::NextToken(t10::ParseDriver* parser) 71 | 72 | typedef YYParser::token token; 73 | 74 | #define yylloc location_ 75 | #define yyterminate() return YYParser::make_TOK_EOF(yylloc) 76 | #define YY_USER_ACTION yylloc.columns(yyleng); 77 | 78 | %} 79 | 80 | %option 8bit 81 | %option batch 82 | %option c++ 83 | %option full 84 | %option noyywrap 85 | %option yyclass="t10::ParseDriver" 86 | 87 | %x string_literal 88 | %x blank 89 | %x comment 90 | 91 | EOL \r\n|\n 92 | DDIGIT [[:digit:]] 93 | ALNUM [[:alnum:]_] 94 | ALPHA [[:alpha:]_] 95 | BLANK [[:blank:]\t] 96 | 97 | DDIGITS {DDIGIT}(_?{DDIGIT})* 98 | EXPONENT {EXP}{SIGN}?{DDIGITS} 99 | 100 | %% 101 | 102 | %{ 103 | yylloc.step(); 104 | %} 105 | 106 | false { 107 | return YYParser::make_TOK_BOOL(false, yylloc); 108 | } 109 | 110 | true { 111 | return YYParser::make_TOK_BOOL(true, yylloc); 112 | } 113 | 114 | /* BEGIN GENERATED TOKENS */ 115 | \( { return YYParser::make_TOK_LPAREN(yylloc); } 116 | \) { return YYParser::make_TOK_RPAREN(yylloc); } 117 | \* { return YYParser::make_TOK_STAR(yylloc); } 118 | /* END GENERATED TOKENS */ 119 | 120 | <> { 121 | return YYParser::make_TOK_EOF(yylloc); 122 | } 123 | 124 | ' { 125 | current_token_.str(""); 126 | BEGIN(string_literal); 127 | } 128 | 129 | \/\/ { 130 | BEGIN(comment); 131 | } 132 | 133 | { 134 | 135 | '' { 136 | current_token_ << '\''; 137 | } 138 | 139 | \' { 140 | BEGIN(INITIAL); 141 | return YYParser::make_TOK_STRING_LITERAL(current_token_.str(), yylloc); 142 | } 143 | 144 | {EOL} { 145 | BEGIN(INITIAL); 146 | yylloc.lines(1); 147 | LexerError("string not terminated: '" + current_token_.str() + "'"); 148 | } 149 | 150 | [[:cntrl:]] { 151 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 152 | } 153 | 154 | <> { 155 | BEGIN(INITIAL); 156 | LexerError("string not terminated: '" + current_token_.str() + "'"); 157 | } 158 | 159 | . { 160 | current_token_ << YYText(); 161 | } 162 | } 163 | 164 | { 165 | {EOL} { 166 | BEGIN(INITIAL); 167 | Unput('\n'); 168 | } 169 | } 170 | 171 | {BLANK}+ { 172 | } 173 | 174 | /* integer literal */ 175 | {DDIGITS} { 176 | return YYParser::make_TOK_INT64(strtol(YYText(), nullptr, 10), yylloc); 177 | } 178 | 179 | /* identifier */ 180 | {ALPHA}(-*{ALNUM})* { 181 | return YYParser::make_TOK_IDENTIFIER(YYText(), yylloc); 182 | } 183 | 184 | /* Any other character. */ 185 | . { 186 | if (isprint(YYText()[0])) { 187 | LexerError(string("unexpected character: '") + YYText() + "'"); 188 | } else { 189 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 190 | } 191 | } 192 | 193 | %% 194 | 195 | namespace t10 { 196 | 197 | using std::istream; 198 | using std::ostream; 199 | 200 | class FatalParseError {}; 201 | 202 | AstNode* parse(istream& input, ostream& errors) { 203 | ParseDriver parser(input, errors); 204 | AstNode* result = nullptr; 205 | YYParser yyparser(&parser, &result); 206 | int ret_val = 1; 207 | try { ret_val = yyparser.parse(); } 208 | catch (FatalParseError) {} 209 | if (ret_val || parser.numErrors() > 0) { 210 | errors << parser.numErrors() << " errors.\n"; 211 | return nullptr; 212 | } 213 | return result; 214 | } 215 | 216 | YYParser::symbol_type yylex(ParseDriver* parser) { 217 | return parser->NextToken(parser); 218 | } 219 | 220 | void YYParser::error(const location_type& loc, const std::string& msg) { 221 | parser->Error(loc, msg); 222 | } 223 | 224 | ParseDriver::ParseDriver(std::istream& source, std::ostream& errors) 225 | : yyFlexLexer(&source) 226 | , source_(&source) 227 | , errors_(errors) 228 | , initial_token_(YYParser::token::TOK_EOF) {} 229 | 230 | ParseDriver::~ParseDriver() { 231 | // This should be done by the parent, but it uses delete, not delete[]... 232 | delete[] yy_state_buf; 233 | yy_state_buf = NULL; 234 | 235 | if (yy_start_stack != NULL) { 236 | free(yy_start_stack); 237 | yy_start_stack = NULL; 238 | } 239 | } 240 | 241 | void ParseDriver::Error( 242 | const YYParser::location_type& loc, const std::string& msg) { 243 | errors_ << "ERROR: " << loc << ":" << msg << std::endl; 244 | num_errors_++; 245 | } 246 | 247 | void ParseDriver::Error(const std::string& msg) { 248 | errors_ << "ERROR: " << msg << std::endl; 249 | num_errors_++; 250 | } 251 | 252 | void ParseDriver::Fatal( 253 | const YYParser::location_type& loc, const std::string& msg) { 254 | Error(loc, msg); 255 | throw FatalParseError(); 256 | } 257 | 258 | void ParseDriver::LexerError(const char* msg) { 259 | Fatal(location_, msg); 260 | } 261 | 262 | void ParseDriver::Unput(char c) { 263 | assert(location_.end.column > 0); 264 | location_.end.column--; 265 | yyunput(c, yytext); 266 | } 267 | 268 | } // namespace t10 269 | /* END LEXER */ 270 | -------------------------------------------------------------------------------- /tests/t11: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class A { 20 | %parseable; 21 | bool b default false syntax(self{true->'b'}|); 22 | syntax('a' b 'c'); 23 | sample('a b c', '(A b:true)'); 24 | sample('a c', '(A b:false)'); 25 | sample('a b', fail); 26 | } -------------------------------------------------------------------------------- /tests/t11.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t11_INCLUDE_ 3 | #define t11_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t11.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t11 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | /* END FORWARD DECLARATIONS */ 30 | 31 | // Base class for t11 AST nodes 32 | class AstNode : public classp::ClasspNode { 33 | public: 34 | string className() override { return "AstNode"; } 35 | AstNode(ParseState parseState) 36 | : parseState(parseState) { 37 | } 38 | 39 | // Write out a bracketed form of this AST from the declared syntax. 40 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 41 | assert(false); 42 | } 43 | 44 | ParseState parseState; 45 | }; 46 | 47 | /* BEGIN CLASS DEFINITIONS */ 48 | class A: public AstNode { 49 | public: 50 | string className() override { return "A"; } 51 | A(ParseState parseState, AttributeMap& keyword_args); 52 | static A* parse(istream& input, ostream& errors); 53 | void printMembers(ostream& out) override; 54 | void format(ostream& out, int precedence) override; 55 | 56 | bool b; 57 | }; 58 | /* END CLASS DEFINITIONS */ 59 | 60 | } // namespace t11 61 | #endif // t11_INCLUDE_ 62 | 63 | /* END HEADER */ 64 | -------------------------------------------------------------------------------- /tests/t11.l: -------------------------------------------------------------------------------- 1 | /* BEGIN LEXER */ 2 | %{ 3 | 4 | #define t11_LEX_CC_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "t11.yacc.hh" 13 | 14 | namespace t11 { 15 | 16 | class AstNode; 17 | 18 | // ParseDriver initiates a parse and contains the state data used during a 19 | // single parsing session (that is, during the parse of one file or string). 20 | class ParseDriver : public yyFlexLexer { 21 | public: 22 | ParseDriver(std::istream& source, std::ostream& errors); 23 | ~ParseDriver() override; 24 | 25 | // A function used by the lexer to report errors. 26 | void Error(const YYParser::location_type& loc, const std::string& msg); 27 | void Error(const std::string& msg); 28 | void Fatal(const YYParser::location_type& loc, const std::string& msg); 29 | void LexerError(const char* msg) override; 30 | void LexerError(const string& msg) { LexerError(msg.c_str()); } 31 | 32 | // Flex-generated function to get the next token from input 33 | virtual YYParser::symbol_type NextToken(ParseDriver* parser); 34 | 35 | // Unput a char and reset location. 36 | virtual void Unput(char c); 37 | 38 | void set_initial_token(YYParser::token_type token) { initial_token_ = token; } 39 | 40 | void consume_initial_token(YYParser::token_type* token) { 41 | *token = initial_token_; 42 | initial_token_ = YYParser::token::TOK_EOF; 43 | } 44 | 45 | int numErrors() { return num_errors_; } 46 | 47 | protected: 48 | const YYParser::location_type* location() { return &location_; } 49 | 50 | private: 51 | std::istream* source_; // Not owned. 52 | std::ostream& errors_; 53 | int num_errors_ = 0; 54 | YYParser::location_type location_; 55 | std::unique_ptr file_name_; 56 | YYParser::token_type initial_token_; 57 | std::stringstream current_token_; // a string token being built up 58 | 59 | // Disallow copy and assign. 60 | ParseDriver(const ParseDriver&) = delete; 61 | void operator=(const ParseDriver&) = delete; 62 | }; 63 | 64 | } // namespace t11 65 | 66 | using t11::YYParser; 67 | 68 | #undef YY_DECL 69 | #define YY_DECL \ 70 | YYParser::symbol_type t11::ParseDriver::NextToken(t11::ParseDriver* parser) 71 | 72 | typedef YYParser::token token; 73 | 74 | #define yylloc location_ 75 | #define yyterminate() return YYParser::make_TOK_EOF(yylloc) 76 | #define YY_USER_ACTION yylloc.columns(yyleng); 77 | 78 | %} 79 | 80 | %option 8bit 81 | %option batch 82 | %option c++ 83 | %option full 84 | %option noyywrap 85 | %option yyclass="t11::ParseDriver" 86 | 87 | %x string_literal 88 | %x blank 89 | %x comment 90 | 91 | EOL \r\n|\n 92 | DDIGIT [[:digit:]] 93 | ALNUM [[:alnum:]_] 94 | ALPHA [[:alpha:]_] 95 | BLANK [[:blank:]\t] 96 | 97 | DDIGITS {DDIGIT}(_?{DDIGIT})* 98 | EXPONENT {EXP}{SIGN}?{DDIGITS} 99 | 100 | %% 101 | 102 | %{ 103 | yylloc.step(); 104 | %} 105 | 106 | false { 107 | return YYParser::make_TOK_BOOL(false, yylloc); 108 | } 109 | 110 | true { 111 | return YYParser::make_TOK_BOOL(true, yylloc); 112 | } 113 | 114 | /* BEGIN GENERATED TOKENS */ 115 | a { return YYParser::make_WORD_a(yylloc); } 116 | b { return YYParser::make_WORD_b(yylloc); } 117 | c { return YYParser::make_WORD_c(yylloc); } 118 | /* END GENERATED TOKENS */ 119 | 120 | <> { 121 | return YYParser::make_TOK_EOF(yylloc); 122 | } 123 | 124 | ' { 125 | current_token_.str(""); 126 | BEGIN(string_literal); 127 | } 128 | 129 | \/\/ { 130 | BEGIN(comment); 131 | } 132 | 133 | { 134 | 135 | '' { 136 | current_token_ << '\''; 137 | } 138 | 139 | \' { 140 | BEGIN(INITIAL); 141 | return YYParser::make_TOK_STRING_LITERAL(current_token_.str(), yylloc); 142 | } 143 | 144 | {EOL} { 145 | BEGIN(INITIAL); 146 | yylloc.lines(1); 147 | LexerError("string not terminated: '" + current_token_.str() + "'"); 148 | } 149 | 150 | [[:cntrl:]] { 151 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 152 | } 153 | 154 | <> { 155 | BEGIN(INITIAL); 156 | LexerError("string not terminated: '" + current_token_.str() + "'"); 157 | } 158 | 159 | . { 160 | current_token_ << YYText(); 161 | } 162 | } 163 | 164 | { 165 | {EOL} { 166 | BEGIN(INITIAL); 167 | Unput('\n'); 168 | } 169 | } 170 | 171 | {BLANK}+ { 172 | } 173 | 174 | /* integer literal */ 175 | {DDIGITS} { 176 | return YYParser::make_TOK_INT64(strtol(YYText(), nullptr, 10), yylloc); 177 | } 178 | 179 | /* identifier */ 180 | {ALPHA}(-*{ALNUM})* { 181 | return YYParser::make_TOK_IDENTIFIER(YYText(), yylloc); 182 | } 183 | 184 | /* Any other character. */ 185 | . { 186 | if (isprint(YYText()[0])) { 187 | LexerError(string("unexpected character: '") + YYText() + "'"); 188 | } else { 189 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 190 | } 191 | } 192 | 193 | %% 194 | 195 | namespace t11 { 196 | 197 | using std::istream; 198 | using std::ostream; 199 | 200 | class FatalParseError {}; 201 | 202 | AstNode* parse(istream& input, ostream& errors) { 203 | ParseDriver parser(input, errors); 204 | AstNode* result = nullptr; 205 | YYParser yyparser(&parser, &result); 206 | int ret_val = 1; 207 | try { ret_val = yyparser.parse(); } 208 | catch (FatalParseError) {} 209 | if (ret_val || parser.numErrors() > 0) { 210 | errors << parser.numErrors() << " errors.\n"; 211 | return nullptr; 212 | } 213 | return result; 214 | } 215 | 216 | YYParser::symbol_type yylex(ParseDriver* parser) { 217 | return parser->NextToken(parser); 218 | } 219 | 220 | void YYParser::error(const location_type& loc, const std::string& msg) { 221 | parser->Error(loc, msg); 222 | } 223 | 224 | ParseDriver::ParseDriver(std::istream& source, std::ostream& errors) 225 | : yyFlexLexer(&source) 226 | , source_(&source) 227 | , errors_(errors) 228 | , initial_token_(YYParser::token::TOK_EOF) {} 229 | 230 | ParseDriver::~ParseDriver() { 231 | // This should be done by the parent, but it uses delete, not delete[]... 232 | delete[] yy_state_buf; 233 | yy_state_buf = NULL; 234 | 235 | if (yy_start_stack != NULL) { 236 | free(yy_start_stack); 237 | yy_start_stack = NULL; 238 | } 239 | } 240 | 241 | void ParseDriver::Error( 242 | const YYParser::location_type& loc, const std::string& msg) { 243 | errors_ << "ERROR: " << loc << ":" << msg << std::endl; 244 | num_errors_++; 245 | } 246 | 247 | void ParseDriver::Error(const std::string& msg) { 248 | errors_ << "ERROR: " << msg << std::endl; 249 | num_errors_++; 250 | } 251 | 252 | void ParseDriver::Fatal( 253 | const YYParser::location_type& loc, const std::string& msg) { 254 | Error(loc, msg); 255 | throw FatalParseError(); 256 | } 257 | 258 | void ParseDriver::LexerError(const char* msg) { 259 | Fatal(location_, msg); 260 | } 261 | 262 | void ParseDriver::Unput(char c) { 263 | assert(location_.end.column > 0); 264 | location_.end.column--; 265 | yyunput(c, yytext); 266 | } 267 | 268 | } // namespace t11 269 | /* END LEXER */ 270 | -------------------------------------------------------------------------------- /tests/t2: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class A { 20 | %parseable; 21 | optional int x; 22 | syntax ( '(' self ')' ); 23 | syntax ( '[' self ']' ); 24 | syntax ( 'just' x ); 25 | syntax ( 'still' x ); 26 | sample('just 5', '(A x:5)'); 27 | sample('(still 5)', '(A x:5)'); 28 | sample('((just 5))', '(A x:5)'); 29 | sample('[(just 5)]', '(A x:5)'); 30 | sample('x 3 y true', '(B x:3 y:true)'); 31 | sample('([(x 3 y true)])', '(B x:3 y:true)'); 32 | sample('([(bar x 3 y true)])', '(B x:3 y:true)'); 33 | sample('x 3 z 4', '(C x:3 z:4)'); 34 | } 35 | 36 | class B: A { 37 | optional bool y; 38 | syntax ('x' x 'y' y); 39 | syntax ( 'bar' self ); 40 | } 41 | class C: A { 42 | optional int z; 43 | syntax ('x' x @@'z'@@ z); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /tests/t2.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t2_INCLUDE_ 3 | #define t2_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t2.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t2 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | class B; 30 | class C; 31 | /* END FORWARD DECLARATIONS */ 32 | 33 | // Base class for t2 AST nodes 34 | class AstNode : public classp::ClasspNode { 35 | public: 36 | string className() override { return "AstNode"; } 37 | AstNode(ParseState parseState) 38 | : parseState(parseState) { 39 | } 40 | 41 | // Write out a bracketed form of this AST from the declared syntax. 42 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 43 | assert(false); 44 | } 45 | 46 | ParseState parseState; 47 | }; 48 | 49 | /* BEGIN CLASS DEFINITIONS */ 50 | class A: public AstNode { 51 | public: 52 | string className() override { return "A"; } 53 | A(ParseState parseState, AttributeMap& keyword_args); 54 | static A* parse(istream& input, ostream& errors); 55 | void printMembers(ostream& out) override; 56 | void format(ostream& out, int precedence) override; 57 | 58 | int x; 59 | bool has_x = false; 60 | }; 61 | 62 | class B: public A { 63 | public: 64 | string className() override { return "B"; } 65 | B(ParseState parseState, AttributeMap& keyword_args); 66 | void printMembers(ostream& out) override; 67 | void format(ostream& out, int precedence) override; 68 | 69 | bool y; 70 | bool has_y = false; 71 | }; 72 | 73 | class C: public A { 74 | public: 75 | string className() override { return "C"; } 76 | C(ParseState parseState, AttributeMap& keyword_args); 77 | void printMembers(ostream& out) override; 78 | void format(ostream& out, int precedence) override; 79 | 80 | int z; 81 | bool has_z = false; 82 | }; 83 | /* END CLASS DEFINITIONS */ 84 | 85 | } // namespace t2 86 | #endif // t2_INCLUDE_ 87 | 88 | /* END HEADER */ 89 | -------------------------------------------------------------------------------- /tests/t3: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class ProcedureDecl { 20 | %parseable; 21 | identifier name; 22 | Declaration arguments[]; 23 | Declaration locals[]; 24 | Statement statements[]; 25 | syntax( 26 | "procedure" name "(" ( arguments * "," ) ")" 27 | "declare" 28 | ( locals * ";" ) 29 | "begin" 30 | ( statements * ) 31 | "end"); 32 | sample('procedure foo (int a) declare int b begin foo(a) end', 33 | '(ProcedureDecl name:foo arguments:[(Declaration type_name:int variable_name:a)] locals:[(Declaration type_name:int variable_name:b)] statements:[(Statement procedure_name:foo arguments:[a])])'); 34 | } 35 | 36 | class Declaration { 37 | identifier type_name; 38 | identifier variable_name; 39 | syntax( type_name variable_name ); 40 | } 41 | 42 | class Statement { 43 | identifier procedure_name; 44 | identifier arguments[]; 45 | syntax( procedure_name "(" (arguments * "," ) ")" ); 46 | } 47 | 48 | class Unparsed { 49 | int foo; 50 | syntax( foo ); 51 | } -------------------------------------------------------------------------------- /tests/t3.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t3_INCLUDE_ 3 | #define t3_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t3.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t3 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class Declaration; 29 | class ProcedureDecl; 30 | class Statement; 31 | class Unparsed; 32 | /* END FORWARD DECLARATIONS */ 33 | 34 | // Base class for t3 AST nodes 35 | class AstNode : public classp::ClasspNode { 36 | public: 37 | string className() override { return "AstNode"; } 38 | AstNode(ParseState parseState) 39 | : parseState(parseState) { 40 | } 41 | 42 | // Write out a bracketed form of this AST from the declared syntax. 43 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 44 | assert(false); 45 | } 46 | 47 | ParseState parseState; 48 | }; 49 | 50 | /* BEGIN CLASS DEFINITIONS */ 51 | class ProcedureDecl: public AstNode { 52 | public: 53 | string className() override { return "ProcedureDecl"; } 54 | ProcedureDecl(ParseState parseState, identifier name, vector arguments, vector locals, vector statements); 55 | static ProcedureDecl* parse(istream& input, ostream& errors); 56 | void printMembers(ostream& out) override; 57 | void format(ostream& out, int precedence) override; 58 | 59 | identifier name; 60 | vector arguments; 61 | vector locals; 62 | vector statements; 63 | }; 64 | 65 | class Declaration: public AstNode { 66 | public: 67 | string className() override { return "Declaration"; } 68 | Declaration(ParseState parseState, identifier type_name, identifier variable_name); 69 | void printMembers(ostream& out) override; 70 | void format(ostream& out, int precedence) override; 71 | 72 | identifier type_name; 73 | identifier variable_name; 74 | }; 75 | 76 | class Statement: public AstNode { 77 | public: 78 | string className() override { return "Statement"; } 79 | Statement(ParseState parseState, identifier procedure_name, vector arguments); 80 | void printMembers(ostream& out) override; 81 | void format(ostream& out, int precedence) override; 82 | 83 | identifier procedure_name; 84 | vector arguments; 85 | }; 86 | 87 | class Unparsed: public AstNode { 88 | public: 89 | string className() override { return "Unparsed"; } 90 | Unparsed(ParseState parseState, int foo); 91 | void printMembers(ostream& out) override; 92 | void format(ostream& out, int precedence) override; 93 | 94 | int foo; 95 | }; 96 | /* END CLASS DEFINITIONS */ 97 | 98 | } // namespace t3 99 | #endif // t3_INCLUDE_ 100 | 101 | /* END HEADER */ 102 | -------------------------------------------------------------------------------- /tests/t4: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class A { 20 | %parseable; 21 | optional int x; 22 | sample('x 1 y 2', '(B x:1 y:2)'); 23 | } 24 | class B: A { 25 | optional int y; 26 | syntax ('x' x 'y' y); 27 | } 28 | class C: A { 29 | optional int z; 30 | syntax ('x' x 'z' z); 31 | } 32 | -------------------------------------------------------------------------------- /tests/t4.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t4_INCLUDE_ 3 | #define t4_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t4.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t4 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | class B; 30 | class C; 31 | /* END FORWARD DECLARATIONS */ 32 | 33 | // Base class for t4 AST nodes 34 | class AstNode : public classp::ClasspNode { 35 | public: 36 | string className() override { return "AstNode"; } 37 | AstNode(ParseState parseState) 38 | : parseState(parseState) { 39 | } 40 | 41 | // Write out a bracketed form of this AST from the declared syntax. 42 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 43 | assert(false); 44 | } 45 | 46 | ParseState parseState; 47 | }; 48 | 49 | /* BEGIN CLASS DEFINITIONS */ 50 | class A: public AstNode { 51 | public: 52 | string className() override { return "A"; } 53 | A(ParseState parseState, AttributeMap& keyword_args); 54 | static A* parse(istream& input, ostream& errors); 55 | void printMembers(ostream& out) override; 56 | 57 | int x; 58 | bool has_x = false; 59 | }; 60 | 61 | class B: public A { 62 | public: 63 | string className() override { return "B"; } 64 | B(ParseState parseState, AttributeMap& keyword_args); 65 | void printMembers(ostream& out) override; 66 | void format(ostream& out, int precedence) override; 67 | 68 | int y; 69 | bool has_y = false; 70 | }; 71 | 72 | class C: public A { 73 | public: 74 | string className() override { return "C"; } 75 | C(ParseState parseState, AttributeMap& keyword_args); 76 | void printMembers(ostream& out) override; 77 | void format(ostream& out, int precedence) override; 78 | 79 | int z; 80 | bool has_z = false; 81 | }; 82 | /* END CLASS DEFINITIONS */ 83 | 84 | } // namespace t4 85 | #endif // t4_INCLUDE_ 86 | 87 | /* END HEADER */ 88 | -------------------------------------------------------------------------------- /tests/t4.l: -------------------------------------------------------------------------------- 1 | /* BEGIN LEXER */ 2 | %{ 3 | 4 | #define t4_LEX_CC_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "t4.yacc.hh" 13 | 14 | namespace t4 { 15 | 16 | class AstNode; 17 | 18 | // ParseDriver initiates a parse and contains the state data used during a 19 | // single parsing session (that is, during the parse of one file or string). 20 | class ParseDriver : public yyFlexLexer { 21 | public: 22 | ParseDriver(std::istream& source, std::ostream& errors); 23 | ~ParseDriver() override; 24 | 25 | // A function used by the lexer to report errors. 26 | void Error(const YYParser::location_type& loc, const std::string& msg); 27 | void Error(const std::string& msg); 28 | void Fatal(const YYParser::location_type& loc, const std::string& msg); 29 | void LexerError(const char* msg) override; 30 | void LexerError(const string& msg) { LexerError(msg.c_str()); } 31 | 32 | // Flex-generated function to get the next token from input 33 | virtual YYParser::symbol_type NextToken(ParseDriver* parser); 34 | 35 | // Unput a char and reset location. 36 | virtual void Unput(char c); 37 | 38 | void set_initial_token(YYParser::token_type token) { initial_token_ = token; } 39 | 40 | void consume_initial_token(YYParser::token_type* token) { 41 | *token = initial_token_; 42 | initial_token_ = YYParser::token::TOK_EOF; 43 | } 44 | 45 | int numErrors() { return num_errors_; } 46 | 47 | protected: 48 | const YYParser::location_type* location() { return &location_; } 49 | 50 | private: 51 | std::istream* source_; // Not owned. 52 | std::ostream& errors_; 53 | int num_errors_ = 0; 54 | YYParser::location_type location_; 55 | std::unique_ptr file_name_; 56 | YYParser::token_type initial_token_; 57 | std::stringstream current_token_; // a string token being built up 58 | 59 | // Disallow copy and assign. 60 | ParseDriver(const ParseDriver&) = delete; 61 | void operator=(const ParseDriver&) = delete; 62 | }; 63 | 64 | } // namespace t4 65 | 66 | using t4::YYParser; 67 | 68 | #undef YY_DECL 69 | #define YY_DECL \ 70 | YYParser::symbol_type t4::ParseDriver::NextToken(t4::ParseDriver* parser) 71 | 72 | typedef YYParser::token token; 73 | 74 | #define yylloc location_ 75 | #define yyterminate() return YYParser::make_TOK_EOF(yylloc) 76 | #define YY_USER_ACTION yylloc.columns(yyleng); 77 | 78 | %} 79 | 80 | %option 8bit 81 | %option batch 82 | %option c++ 83 | %option full 84 | %option noyywrap 85 | %option yyclass="t4::ParseDriver" 86 | 87 | %x string_literal 88 | %x blank 89 | %x comment 90 | 91 | EOL \r\n|\n 92 | DDIGIT [[:digit:]] 93 | ALNUM [[:alnum:]_] 94 | ALPHA [[:alpha:]_] 95 | BLANK [[:blank:]\t] 96 | 97 | DDIGITS {DDIGIT}(_?{DDIGIT})* 98 | EXPONENT {EXP}{SIGN}?{DDIGITS} 99 | 100 | %% 101 | 102 | %{ 103 | yylloc.step(); 104 | %} 105 | 106 | false { 107 | return YYParser::make_TOK_BOOL(false, yylloc); 108 | } 109 | 110 | true { 111 | return YYParser::make_TOK_BOOL(true, yylloc); 112 | } 113 | 114 | /* BEGIN GENERATED TOKENS */ 115 | x { return YYParser::make_WORD_x(yylloc); } 116 | y { return YYParser::make_WORD_y(yylloc); } 117 | z { return YYParser::make_WORD_z(yylloc); } 118 | /* END GENERATED TOKENS */ 119 | 120 | <> { 121 | return YYParser::make_TOK_EOF(yylloc); 122 | } 123 | 124 | ' { 125 | current_token_.str(""); 126 | BEGIN(string_literal); 127 | } 128 | 129 | \/\/ { 130 | BEGIN(comment); 131 | } 132 | 133 | { 134 | 135 | '' { 136 | current_token_ << '\''; 137 | } 138 | 139 | \' { 140 | BEGIN(INITIAL); 141 | return YYParser::make_TOK_STRING_LITERAL(current_token_.str(), yylloc); 142 | } 143 | 144 | {EOL} { 145 | BEGIN(INITIAL); 146 | yylloc.lines(1); 147 | LexerError("string not terminated: '" + current_token_.str() + "'"); 148 | } 149 | 150 | [[:cntrl:]] { 151 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 152 | } 153 | 154 | <> { 155 | BEGIN(INITIAL); 156 | LexerError("string not terminated: '" + current_token_.str() + "'"); 157 | } 158 | 159 | . { 160 | current_token_ << YYText(); 161 | } 162 | } 163 | 164 | { 165 | {EOL} { 166 | BEGIN(INITIAL); 167 | Unput('\n'); 168 | } 169 | } 170 | 171 | {BLANK}+ { 172 | } 173 | 174 | /* integer literal */ 175 | {DDIGITS} { 176 | return YYParser::make_TOK_INT64(strtol(YYText(), nullptr, 10), yylloc); 177 | } 178 | 179 | /* identifier */ 180 | {ALPHA}(-*{ALNUM})* { 181 | return YYParser::make_TOK_IDENTIFIER(YYText(), yylloc); 182 | } 183 | 184 | /* Any other character. */ 185 | . { 186 | if (isprint(YYText()[0])) { 187 | LexerError(string("unexpected character: '") + YYText() + "'"); 188 | } else { 189 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 190 | } 191 | } 192 | 193 | %% 194 | 195 | namespace t4 { 196 | 197 | using std::istream; 198 | using std::ostream; 199 | 200 | class FatalParseError {}; 201 | 202 | AstNode* parse(istream& input, ostream& errors) { 203 | ParseDriver parser(input, errors); 204 | AstNode* result = nullptr; 205 | YYParser yyparser(&parser, &result); 206 | int ret_val = 1; 207 | try { ret_val = yyparser.parse(); } 208 | catch (FatalParseError) {} 209 | if (ret_val || parser.numErrors() > 0) { 210 | errors << parser.numErrors() << " errors.\n"; 211 | return nullptr; 212 | } 213 | return result; 214 | } 215 | 216 | YYParser::symbol_type yylex(ParseDriver* parser) { 217 | return parser->NextToken(parser); 218 | } 219 | 220 | void YYParser::error(const location_type& loc, const std::string& msg) { 221 | parser->Error(loc, msg); 222 | } 223 | 224 | ParseDriver::ParseDriver(std::istream& source, std::ostream& errors) 225 | : yyFlexLexer(&source) 226 | , source_(&source) 227 | , errors_(errors) 228 | , initial_token_(YYParser::token::TOK_EOF) {} 229 | 230 | ParseDriver::~ParseDriver() { 231 | // This should be done by the parent, but it uses delete, not delete[]... 232 | delete[] yy_state_buf; 233 | yy_state_buf = NULL; 234 | 235 | if (yy_start_stack != NULL) { 236 | free(yy_start_stack); 237 | yy_start_stack = NULL; 238 | } 239 | } 240 | 241 | void ParseDriver::Error( 242 | const YYParser::location_type& loc, const std::string& msg) { 243 | errors_ << "ERROR: " << loc << ":" << msg << std::endl; 244 | num_errors_++; 245 | } 246 | 247 | void ParseDriver::Error(const std::string& msg) { 248 | errors_ << "ERROR: " << msg << std::endl; 249 | num_errors_++; 250 | } 251 | 252 | void ParseDriver::Fatal( 253 | const YYParser::location_type& loc, const std::string& msg) { 254 | Error(loc, msg); 255 | throw FatalParseError(); 256 | } 257 | 258 | void ParseDriver::LexerError(const char* msg) { 259 | Fatal(location_, msg); 260 | } 261 | 262 | void ParseDriver::Unput(char c) { 263 | assert(location_.end.column > 0); 264 | location_.end.column--; 265 | yyunput(c, yytext); 266 | } 267 | 268 | } // namespace t4 269 | /* END LEXER */ 270 | -------------------------------------------------------------------------------- /tests/t5: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class Query { 20 | %parseable; 21 | Expression select_list[] syntax(self+','); 22 | Expression from_list[] syntax('FROM' (self+',')|); 23 | optional Expression where_clause syntax('WHERE' self|); 24 | Expression group_by[] syntax(self+','); 25 | syntax('SELECT' select_list from_list where_clause ('GROUP' 'BY' group_by|)); 26 | sample('SELECT a, b FROM t1, t2', '(Query select_list:[(Expression id:a), (Expression id:b)] from_list:[(Expression id:t1), (Expression id:t2)]where_clause[not defined] group_by:[])'); 27 | } 28 | 29 | class Expression { 30 | identifier id syntax(self); 31 | syntax(id); 32 | } 33 | -------------------------------------------------------------------------------- /tests/t5.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t5_INCLUDE_ 3 | #define t5_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t5.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t5 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class Expression; 29 | class Query; 30 | /* END FORWARD DECLARATIONS */ 31 | 32 | // Base class for t5 AST nodes 33 | class AstNode : public classp::ClasspNode { 34 | public: 35 | string className() override { return "AstNode"; } 36 | AstNode(ParseState parseState) 37 | : parseState(parseState) { 38 | } 39 | 40 | // Write out a bracketed form of this AST from the declared syntax. 41 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 42 | assert(false); 43 | } 44 | 45 | ParseState parseState; 46 | }; 47 | 48 | /* BEGIN CLASS DEFINITIONS */ 49 | class Query: public AstNode { 50 | public: 51 | string className() override { return "Query"; } 52 | Query(ParseState parseState, vector select_list, AttributeMap& keyword_args); 53 | static Query* parse(istream& input, ostream& errors); 54 | void printMembers(ostream& out) override; 55 | void format(ostream& out, int precedence) override; 56 | 57 | vector select_list; 58 | vector from_list; 59 | Expression* where_clause = nullptr; 60 | vector group_by; 61 | bool has_where_clause = false; 62 | }; 63 | 64 | class Expression: public AstNode { 65 | public: 66 | string className() override { return "Expression"; } 67 | Expression(ParseState parseState, identifier id); 68 | void printMembers(ostream& out) override; 69 | void format(ostream& out, int precedence) override; 70 | 71 | identifier id; 72 | }; 73 | /* END CLASS DEFINITIONS */ 74 | 75 | } // namespace t5 76 | #endif // t5_INCLUDE_ 77 | 78 | /* END HEADER */ 79 | -------------------------------------------------------------------------------- /tests/t6: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class A { 20 | int a1[]; 21 | syntax('<' a1 '>' * '|' '#'); 22 | } 23 | 24 | class B { 25 | int a1[]; 26 | int a2[]; 27 | syntax('<' a1 ',' a2 '>' * '|'); 28 | } 29 | 30 | class C { 31 | int a1[]; 32 | int a2[]; 33 | syntax('<' a1 ',' a2 '>' *); 34 | } 35 | 36 | class D { 37 | int a1[]; 38 | int a2[]; 39 | int a3[]; 40 | int a4[]; 41 | syntax(('<' a1 ',' a2 '>' +) ('<' a3 ',' a4 '>' + '|')); 42 | } 43 | 44 | class E { 45 | syntax(('<' '>' *)('<' '>' + ',')); 46 | } 47 | -------------------------------------------------------------------------------- /tests/t6.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t6_INCLUDE_ 3 | #define t6_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t6.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t6 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | class B; 30 | class C; 31 | class D; 32 | class E; 33 | /* END FORWARD DECLARATIONS */ 34 | 35 | // Base class for t6 AST nodes 36 | class AstNode : public classp::ClasspNode { 37 | public: 38 | string className() override { return "AstNode"; } 39 | AstNode(ParseState parseState) 40 | : parseState(parseState) { 41 | } 42 | 43 | // Write out a bracketed form of this AST from the declared syntax. 44 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 45 | assert(false); 46 | } 47 | 48 | ParseState parseState; 49 | }; 50 | 51 | /* BEGIN CLASS DEFINITIONS */ 52 | class A: public AstNode { 53 | public: 54 | string className() override { return "A"; } 55 | A(ParseState parseState, AttributeMap& keyword_args); 56 | void printMembers(ostream& out) override; 57 | void format(ostream& out, int precedence) override; 58 | 59 | vector a1; 60 | }; 61 | 62 | class B: public AstNode { 63 | public: 64 | string className() override { return "B"; } 65 | B(ParseState parseState, AttributeMap& keyword_args); 66 | void printMembers(ostream& out) override; 67 | void format(ostream& out, int precedence) override; 68 | 69 | vector a1; 70 | vector a2; 71 | }; 72 | 73 | class C: public AstNode { 74 | public: 75 | string className() override { return "C"; } 76 | C(ParseState parseState, AttributeMap& keyword_args); 77 | void printMembers(ostream& out) override; 78 | void format(ostream& out, int precedence) override; 79 | 80 | vector a1; 81 | vector a2; 82 | }; 83 | 84 | class D: public AstNode { 85 | public: 86 | string className() override { return "D"; } 87 | D(ParseState parseState, AttributeMap& keyword_args); 88 | void printMembers(ostream& out) override; 89 | void format(ostream& out, int precedence) override; 90 | 91 | vector a1; 92 | vector a2; 93 | vector a3; 94 | vector a4; 95 | }; 96 | 97 | class E: public AstNode { 98 | public: 99 | string className() override { return "E"; } 100 | E(ParseState parseState); 101 | void printMembers(ostream& out) override; 102 | void format(ostream& out, int precedence) override; 103 | 104 | }; 105 | /* END CLASS DEFINITIONS */ 106 | 107 | } // namespace t6 108 | #endif // t6_INCLUDE_ 109 | 110 | /* END HEADER */ 111 | -------------------------------------------------------------------------------- /tests/t7: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class A { 20 | optional int x; 21 | optional int y; 22 | syntax((x|y)*); 23 | } 24 | class B { 25 | int a1[]; 26 | optional int x; 27 | syntax((a1|x)+); 28 | } 29 | class C { 30 | A a1[]; 31 | A a2[]; 32 | A a3[]; 33 | optional int x; 34 | optional int y; 35 | optional int z; 36 | syntax((a1 '+' a2|x '*' y| a1 '<' z)+','); 37 | } 38 | -------------------------------------------------------------------------------- /tests/t7.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t7_INCLUDE_ 3 | #define t7_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t7.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t7 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | class B; 30 | class C; 31 | /* END FORWARD DECLARATIONS */ 32 | 33 | // Base class for t7 AST nodes 34 | class AstNode : public classp::ClasspNode { 35 | public: 36 | string className() override { return "AstNode"; } 37 | AstNode(ParseState parseState) 38 | : parseState(parseState) { 39 | } 40 | 41 | // Write out a bracketed form of this AST from the declared syntax. 42 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 43 | assert(false); 44 | } 45 | 46 | ParseState parseState; 47 | }; 48 | 49 | /* BEGIN CLASS DEFINITIONS */ 50 | class A: public AstNode { 51 | public: 52 | string className() override { return "A"; } 53 | A(ParseState parseState, AttributeMap& keyword_args); 54 | void printMembers(ostream& out) override; 55 | void format(ostream& out, int precedence) override; 56 | 57 | int x; 58 | int y; 59 | bool has_x = false; 60 | bool has_y = false; 61 | }; 62 | 63 | class B: public AstNode { 64 | public: 65 | string className() override { return "B"; } 66 | B(ParseState parseState, AttributeMap& keyword_args); 67 | void printMembers(ostream& out) override; 68 | void format(ostream& out, int precedence) override; 69 | 70 | vector a1; 71 | int x; 72 | bool has_x = false; 73 | }; 74 | 75 | class C: public AstNode { 76 | public: 77 | string className() override { return "C"; } 78 | C(ParseState parseState, vector a3, AttributeMap& keyword_args); 79 | void printMembers(ostream& out) override; 80 | void format(ostream& out, int precedence) override; 81 | 82 | vector a1; 83 | vector a2; 84 | vector a3; 85 | int x; 86 | int y; 87 | int z; 88 | bool has_x = false; 89 | bool has_y = false; 90 | bool has_z = false; 91 | }; 92 | /* END CLASS DEFINITIONS */ 93 | 94 | } // namespace t7 95 | #endif // t7_INCLUDE_ 96 | 97 | /* END HEADER */ 98 | -------------------------------------------------------------------------------- /tests/t8: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class A { 20 | int a1; 21 | optional int a2; 22 | int a3 default 0; 23 | int a4[]; 24 | %parseable; 25 | } 26 | class B: A { 27 | int b1; 28 | optional int b2; 29 | int b3 default 0; 30 | int b4[]; 31 | } 32 | class C: B { 33 | int c1; 34 | optional int c2; 35 | int c3 default 0; 36 | int c4[]; 37 | optional int c5; 38 | int c6 default 0; 39 | int c7[]; 40 | int c8 default 0; 41 | int c9[]; 42 | syntax(a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 (c5|) (c6|c7) ((c8|c9)*)) %left 1; 43 | } 44 | -------------------------------------------------------------------------------- /tests/t8.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t8_INCLUDE_ 3 | #define t8_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t8.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t8 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | class B; 30 | class C; 31 | /* END FORWARD DECLARATIONS */ 32 | 33 | // Base class for t8 AST nodes 34 | class AstNode : public classp::ClasspNode { 35 | public: 36 | string className() override { return "AstNode"; } 37 | AstNode(ParseState parseState) 38 | : parseState(parseState) { 39 | } 40 | 41 | // Write out a bracketed form of this AST from the declared syntax. 42 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 43 | assert(false); 44 | } 45 | 46 | ParseState parseState; 47 | }; 48 | 49 | /* BEGIN CLASS DEFINITIONS */ 50 | class A: public AstNode { 51 | public: 52 | string className() override { return "A"; } 53 | A(ParseState parseState, int a1, vector a4, AttributeMap& keyword_args); 54 | static A* parse(istream& input, ostream& errors); 55 | void printMembers(ostream& out) override; 56 | void bracketFormat(ostream& out, AstNode* self) override; 57 | 58 | int a1; 59 | int a2; 60 | int a3; 61 | vector a4; 62 | bool has_a2 = false; 63 | }; 64 | 65 | class B: public A { 66 | public: 67 | string className() override { return "B"; } 68 | B(ParseState parseState, int a1, vector a4, int b1, vector b4, AttributeMap& keyword_args); 69 | void printMembers(ostream& out) override; 70 | 71 | int b1; 72 | int b2; 73 | int b3; 74 | vector b4; 75 | bool has_b2 = false; 76 | }; 77 | 78 | class C: public B { 79 | public: 80 | string className() override { return "C"; } 81 | C(ParseState parseState, int a1, vector a4, int b1, vector b4, int c1, vector c4, AttributeMap& keyword_args); 82 | void printMembers(ostream& out) override; 83 | void format(ostream& out, int precedence) override; 84 | 85 | int c1; 86 | int c2; 87 | int c3; 88 | vector c4; 89 | int c5; 90 | int c6; 91 | vector c7; 92 | int c8; 93 | vector c9; 94 | bool has_c2 = false; 95 | bool has_c5 = false; 96 | }; 97 | /* END CLASS DEFINITIONS */ 98 | 99 | } // namespace t8 100 | #endif // t8_INCLUDE_ 101 | 102 | /* END HEADER */ 103 | -------------------------------------------------------------------------------- /tests/t8.l: -------------------------------------------------------------------------------- 1 | /* BEGIN LEXER */ 2 | %{ 3 | 4 | #define t8_LEX_CC_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "t8.yacc.hh" 13 | 14 | namespace t8 { 15 | 16 | class AstNode; 17 | 18 | // ParseDriver initiates a parse and contains the state data used during a 19 | // single parsing session (that is, during the parse of one file or string). 20 | class ParseDriver : public yyFlexLexer { 21 | public: 22 | ParseDriver(std::istream& source, std::ostream& errors); 23 | ~ParseDriver() override; 24 | 25 | // A function used by the lexer to report errors. 26 | void Error(const YYParser::location_type& loc, const std::string& msg); 27 | void Error(const std::string& msg); 28 | void Fatal(const YYParser::location_type& loc, const std::string& msg); 29 | void LexerError(const char* msg) override; 30 | void LexerError(const string& msg) { LexerError(msg.c_str()); } 31 | 32 | // Flex-generated function to get the next token from input 33 | virtual YYParser::symbol_type NextToken(ParseDriver* parser); 34 | 35 | // Unput a char and reset location. 36 | virtual void Unput(char c); 37 | 38 | void set_initial_token(YYParser::token_type token) { initial_token_ = token; } 39 | 40 | void consume_initial_token(YYParser::token_type* token) { 41 | *token = initial_token_; 42 | initial_token_ = YYParser::token::TOK_EOF; 43 | } 44 | 45 | int numErrors() { return num_errors_; } 46 | 47 | protected: 48 | const YYParser::location_type* location() { return &location_; } 49 | 50 | private: 51 | std::istream* source_; // Not owned. 52 | std::ostream& errors_; 53 | int num_errors_ = 0; 54 | YYParser::location_type location_; 55 | std::unique_ptr file_name_; 56 | YYParser::token_type initial_token_; 57 | std::stringstream current_token_; // a string token being built up 58 | 59 | // Disallow copy and assign. 60 | ParseDriver(const ParseDriver&) = delete; 61 | void operator=(const ParseDriver&) = delete; 62 | }; 63 | 64 | } // namespace t8 65 | 66 | using t8::YYParser; 67 | 68 | #undef YY_DECL 69 | #define YY_DECL \ 70 | YYParser::symbol_type t8::ParseDriver::NextToken(t8::ParseDriver* parser) 71 | 72 | typedef YYParser::token token; 73 | 74 | #define yylloc location_ 75 | #define yyterminate() return YYParser::make_TOK_EOF(yylloc) 76 | #define YY_USER_ACTION yylloc.columns(yyleng); 77 | 78 | %} 79 | 80 | %option 8bit 81 | %option batch 82 | %option c++ 83 | %option full 84 | %option noyywrap 85 | %option yyclass="t8::ParseDriver" 86 | 87 | %x string_literal 88 | %x blank 89 | %x comment 90 | 91 | EOL \r\n|\n 92 | DDIGIT [[:digit:]] 93 | ALNUM [[:alnum:]_] 94 | ALPHA [[:alpha:]_] 95 | BLANK [[:blank:]\t] 96 | 97 | DDIGITS {DDIGIT}(_?{DDIGIT})* 98 | EXPONENT {EXP}{SIGN}?{DDIGITS} 99 | 100 | %% 101 | 102 | %{ 103 | yylloc.step(); 104 | %} 105 | 106 | false { 107 | return YYParser::make_TOK_BOOL(false, yylloc); 108 | } 109 | 110 | true { 111 | return YYParser::make_TOK_BOOL(true, yylloc); 112 | } 113 | 114 | /* BEGIN GENERATED TOKENS */ 115 | /* END GENERATED TOKENS */ 116 | 117 | <> { 118 | return YYParser::make_TOK_EOF(yylloc); 119 | } 120 | 121 | ' { 122 | current_token_.str(""); 123 | BEGIN(string_literal); 124 | } 125 | 126 | \/\/ { 127 | BEGIN(comment); 128 | } 129 | 130 | { 131 | 132 | '' { 133 | current_token_ << '\''; 134 | } 135 | 136 | \' { 137 | BEGIN(INITIAL); 138 | return YYParser::make_TOK_STRING_LITERAL(current_token_.str(), yylloc); 139 | } 140 | 141 | {EOL} { 142 | BEGIN(INITIAL); 143 | yylloc.lines(1); 144 | LexerError("string not terminated: '" + current_token_.str() + "'"); 145 | } 146 | 147 | [[:cntrl:]] { 148 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 149 | } 150 | 151 | <> { 152 | BEGIN(INITIAL); 153 | LexerError("string not terminated: '" + current_token_.str() + "'"); 154 | } 155 | 156 | . { 157 | current_token_ << YYText(); 158 | } 159 | } 160 | 161 | { 162 | {EOL} { 163 | BEGIN(INITIAL); 164 | Unput('\n'); 165 | } 166 | } 167 | 168 | {BLANK}+ { 169 | } 170 | 171 | /* integer literal */ 172 | {DDIGITS} { 173 | return YYParser::make_TOK_INT64(strtol(YYText(), nullptr, 10), yylloc); 174 | } 175 | 176 | /* identifier */ 177 | {ALPHA}(-*{ALNUM})* { 178 | return YYParser::make_TOK_IDENTIFIER(YYText(), yylloc); 179 | } 180 | 181 | /* Any other character. */ 182 | . { 183 | if (isprint(YYText()[0])) { 184 | LexerError(string("unexpected character: '") + YYText() + "'"); 185 | } else { 186 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 187 | } 188 | } 189 | 190 | %% 191 | 192 | namespace t8 { 193 | 194 | using std::istream; 195 | using std::ostream; 196 | 197 | class FatalParseError {}; 198 | 199 | AstNode* parse(istream& input, ostream& errors) { 200 | ParseDriver parser(input, errors); 201 | AstNode* result = nullptr; 202 | YYParser yyparser(&parser, &result); 203 | int ret_val = 1; 204 | try { ret_val = yyparser.parse(); } 205 | catch (FatalParseError) {} 206 | if (ret_val || parser.numErrors() > 0) { 207 | errors << parser.numErrors() << " errors.\n"; 208 | return nullptr; 209 | } 210 | return result; 211 | } 212 | 213 | YYParser::symbol_type yylex(ParseDriver* parser) { 214 | return parser->NextToken(parser); 215 | } 216 | 217 | void YYParser::error(const location_type& loc, const std::string& msg) { 218 | parser->Error(loc, msg); 219 | } 220 | 221 | ParseDriver::ParseDriver(std::istream& source, std::ostream& errors) 222 | : yyFlexLexer(&source) 223 | , source_(&source) 224 | , errors_(errors) 225 | , initial_token_(YYParser::token::TOK_EOF) {} 226 | 227 | ParseDriver::~ParseDriver() { 228 | // This should be done by the parent, but it uses delete, not delete[]... 229 | delete[] yy_state_buf; 230 | yy_state_buf = NULL; 231 | 232 | if (yy_start_stack != NULL) { 233 | free(yy_start_stack); 234 | yy_start_stack = NULL; 235 | } 236 | } 237 | 238 | void ParseDriver::Error( 239 | const YYParser::location_type& loc, const std::string& msg) { 240 | errors_ << "ERROR: " << loc << ":" << msg << std::endl; 241 | num_errors_++; 242 | } 243 | 244 | void ParseDriver::Error(const std::string& msg) { 245 | errors_ << "ERROR: " << msg << std::endl; 246 | num_errors_++; 247 | } 248 | 249 | void ParseDriver::Fatal( 250 | const YYParser::location_type& loc, const std::string& msg) { 251 | Error(loc, msg); 252 | throw FatalParseError(); 253 | } 254 | 255 | void ParseDriver::LexerError(const char* msg) { 256 | Fatal(location_, msg); 257 | } 258 | 259 | void ParseDriver::Unput(char c) { 260 | assert(location_.end.column > 0); 261 | location_.end.column--; 262 | yyunput(c, yytext); 263 | } 264 | 265 | } // namespace t8 266 | /* END LEXER */ 267 | -------------------------------------------------------------------------------- /tests/t9: -------------------------------------------------------------------------------- 1 | // This file is a part of the Classp parser, formatter, and AST generator. 2 | // Description: Used to generate skeleton-generator.h from the skeleton files. 3 | // 4 | // Copyright 2015 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | class A { 20 | int a1; 21 | optional int a2; 22 | int a3 default 0; 23 | int a4[]; 24 | %parseable; 25 | } 26 | class B: A { 27 | int b1; 28 | optional int b2; 29 | int b3 default 0; 30 | int b4[]; 31 | } 32 | class C: B { 33 | int c1; 34 | optional int c2; 35 | int c3 default 0; 36 | int c4[]; 37 | optional int c5; 38 | int c6 default 0; 39 | int c7[]; 40 | int c8 default 0; 41 | int c9[]; 42 | syntax(a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 (c5|) (c6|c7) ((c8|c9)*)); 43 | } 44 | -------------------------------------------------------------------------------- /tests/t9.h: -------------------------------------------------------------------------------- 1 | /* BEGIN HEADER */ 2 | #ifndef t9_INCLUDE_ 3 | #define t9_INCLUDE_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "classp.h" 10 | 11 | // Include files generated by bison 12 | #include "t9.yacc.hh" 13 | #include "location.hh" 14 | #include "position.hh" 15 | 16 | namespace t9 { 17 | using std::istream; 18 | using std::ostream; 19 | using classp::classpPrint; 20 | using classp::classpFormat; 21 | using classp::AttributeMap; 22 | 23 | // Location and state information from the parser. 24 | typedef location ParseState; 25 | 26 | class AstNode; 27 | /* BEGIN FORWARD DECLARATIONS */ 28 | class A; 29 | class B; 30 | class C; 31 | /* END FORWARD DECLARATIONS */ 32 | 33 | // Base class for t9 AST nodes 34 | class AstNode : public classp::ClasspNode { 35 | public: 36 | string className() override { return "AstNode"; } 37 | AstNode(ParseState parseState) 38 | : parseState(parseState) { 39 | } 40 | 41 | // Write out a bracketed form of this AST from the declared syntax. 42 | virtual void bracketFormat(std::ostream& out, AstNode* self) { 43 | assert(false); 44 | } 45 | 46 | ParseState parseState; 47 | }; 48 | 49 | /* BEGIN CLASS DEFINITIONS */ 50 | class A: public AstNode { 51 | public: 52 | string className() override { return "A"; } 53 | A(ParseState parseState, int a1, vector a4, AttributeMap& keyword_args); 54 | static A* parse(istream& input, ostream& errors); 55 | void printMembers(ostream& out) override; 56 | 57 | int a1; 58 | int a2; 59 | int a3; 60 | vector a4; 61 | bool has_a2 = false; 62 | }; 63 | 64 | class B: public A { 65 | public: 66 | string className() override { return "B"; } 67 | B(ParseState parseState, int a1, vector a4, int b1, vector b4, AttributeMap& keyword_args); 68 | void printMembers(ostream& out) override; 69 | 70 | int b1; 71 | int b2; 72 | int b3; 73 | vector b4; 74 | bool has_b2 = false; 75 | }; 76 | 77 | class C: public B { 78 | public: 79 | string className() override { return "C"; } 80 | C(ParseState parseState, int a1, vector a4, int b1, vector b4, int c1, vector c4, AttributeMap& keyword_args); 81 | void printMembers(ostream& out) override; 82 | void format(ostream& out, int precedence) override; 83 | 84 | int c1; 85 | int c2; 86 | int c3; 87 | vector c4; 88 | int c5; 89 | int c6; 90 | vector c7; 91 | int c8; 92 | vector c9; 93 | bool has_c2 = false; 94 | bool has_c5 = false; 95 | }; 96 | /* END CLASS DEFINITIONS */ 97 | 98 | } // namespace t9 99 | #endif // t9_INCLUDE_ 100 | 101 | /* END HEADER */ 102 | -------------------------------------------------------------------------------- /tests/t9.l: -------------------------------------------------------------------------------- 1 | /* BEGIN LEXER */ 2 | %{ 3 | 4 | #define t9_LEX_CC_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "t9.yacc.hh" 13 | 14 | namespace t9 { 15 | 16 | class AstNode; 17 | 18 | // ParseDriver initiates a parse and contains the state data used during a 19 | // single parsing session (that is, during the parse of one file or string). 20 | class ParseDriver : public yyFlexLexer { 21 | public: 22 | ParseDriver(std::istream& source, std::ostream& errors); 23 | ~ParseDriver() override; 24 | 25 | // A function used by the lexer to report errors. 26 | void Error(const YYParser::location_type& loc, const std::string& msg); 27 | void Error(const std::string& msg); 28 | void Fatal(const YYParser::location_type& loc, const std::string& msg); 29 | void LexerError(const char* msg) override; 30 | void LexerError(const string& msg) { LexerError(msg.c_str()); } 31 | 32 | // Flex-generated function to get the next token from input 33 | virtual YYParser::symbol_type NextToken(ParseDriver* parser); 34 | 35 | // Unput a char and reset location. 36 | virtual void Unput(char c); 37 | 38 | void set_initial_token(YYParser::token_type token) { initial_token_ = token; } 39 | 40 | void consume_initial_token(YYParser::token_type* token) { 41 | *token = initial_token_; 42 | initial_token_ = YYParser::token::TOK_EOF; 43 | } 44 | 45 | int numErrors() { return num_errors_; } 46 | 47 | protected: 48 | const YYParser::location_type* location() { return &location_; } 49 | 50 | private: 51 | std::istream* source_; // Not owned. 52 | std::ostream& errors_; 53 | int num_errors_ = 0; 54 | YYParser::location_type location_; 55 | std::unique_ptr file_name_; 56 | YYParser::token_type initial_token_; 57 | std::stringstream current_token_; // a string token being built up 58 | 59 | // Disallow copy and assign. 60 | ParseDriver(const ParseDriver&) = delete; 61 | void operator=(const ParseDriver&) = delete; 62 | }; 63 | 64 | } // namespace t9 65 | 66 | using t9::YYParser; 67 | 68 | #undef YY_DECL 69 | #define YY_DECL \ 70 | YYParser::symbol_type t9::ParseDriver::NextToken(t9::ParseDriver* parser) 71 | 72 | typedef YYParser::token token; 73 | 74 | #define yylloc location_ 75 | #define yyterminate() return YYParser::make_TOK_EOF(yylloc) 76 | #define YY_USER_ACTION yylloc.columns(yyleng); 77 | 78 | %} 79 | 80 | %option 8bit 81 | %option batch 82 | %option c++ 83 | %option full 84 | %option noyywrap 85 | %option yyclass="t9::ParseDriver" 86 | 87 | %x string_literal 88 | %x blank 89 | %x comment 90 | 91 | EOL \r\n|\n 92 | DDIGIT [[:digit:]] 93 | ALNUM [[:alnum:]_] 94 | ALPHA [[:alpha:]_] 95 | BLANK [[:blank:]\t] 96 | 97 | DDIGITS {DDIGIT}(_?{DDIGIT})* 98 | EXPONENT {EXP}{SIGN}?{DDIGITS} 99 | 100 | %% 101 | 102 | %{ 103 | yylloc.step(); 104 | %} 105 | 106 | false { 107 | return YYParser::make_TOK_BOOL(false, yylloc); 108 | } 109 | 110 | true { 111 | return YYParser::make_TOK_BOOL(true, yylloc); 112 | } 113 | 114 | /* BEGIN GENERATED TOKENS */ 115 | /* END GENERATED TOKENS */ 116 | 117 | <> { 118 | return YYParser::make_TOK_EOF(yylloc); 119 | } 120 | 121 | ' { 122 | current_token_.str(""); 123 | BEGIN(string_literal); 124 | } 125 | 126 | \/\/ { 127 | BEGIN(comment); 128 | } 129 | 130 | { 131 | 132 | '' { 133 | current_token_ << '\''; 134 | } 135 | 136 | \' { 137 | BEGIN(INITIAL); 138 | return YYParser::make_TOK_STRING_LITERAL(current_token_.str(), yylloc); 139 | } 140 | 141 | {EOL} { 142 | BEGIN(INITIAL); 143 | yylloc.lines(1); 144 | LexerError("string not terminated: '" + current_token_.str() + "'"); 145 | } 146 | 147 | [[:cntrl:]] { 148 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 149 | } 150 | 151 | <> { 152 | BEGIN(INITIAL); 153 | LexerError("string not terminated: '" + current_token_.str() + "'"); 154 | } 155 | 156 | . { 157 | current_token_ << YYText(); 158 | } 159 | } 160 | 161 | { 162 | {EOL} { 163 | BEGIN(INITIAL); 164 | Unput('\n'); 165 | } 166 | } 167 | 168 | {BLANK}+ { 169 | } 170 | 171 | /* integer literal */ 172 | {DDIGITS} { 173 | return YYParser::make_TOK_INT64(strtol(YYText(), nullptr, 10), yylloc); 174 | } 175 | 176 | /* identifier */ 177 | {ALPHA}(-*{ALNUM})* { 178 | return YYParser::make_TOK_IDENTIFIER(YYText(), yylloc); 179 | } 180 | 181 | /* Any other character. */ 182 | . { 183 | if (isprint(YYText()[0])) { 184 | LexerError(string("unexpected character: '") + YYText() + "'"); 185 | } else { 186 | LexerError("unexpected character: " + std::to_string(YYText()[0])); 187 | } 188 | } 189 | 190 | %% 191 | 192 | namespace t9 { 193 | 194 | using std::istream; 195 | using std::ostream; 196 | 197 | class FatalParseError {}; 198 | 199 | AstNode* parse(istream& input, ostream& errors) { 200 | ParseDriver parser(input, errors); 201 | AstNode* result = nullptr; 202 | YYParser yyparser(&parser, &result); 203 | int ret_val = 1; 204 | try { ret_val = yyparser.parse(); } 205 | catch (FatalParseError) {} 206 | if (ret_val || parser.numErrors() > 0) { 207 | errors << parser.numErrors() << " errors.\n"; 208 | return nullptr; 209 | } 210 | return result; 211 | } 212 | 213 | YYParser::symbol_type yylex(ParseDriver* parser) { 214 | return parser->NextToken(parser); 215 | } 216 | 217 | void YYParser::error(const location_type& loc, const std::string& msg) { 218 | parser->Error(loc, msg); 219 | } 220 | 221 | ParseDriver::ParseDriver(std::istream& source, std::ostream& errors) 222 | : yyFlexLexer(&source) 223 | , source_(&source) 224 | , errors_(errors) 225 | , initial_token_(YYParser::token::TOK_EOF) {} 226 | 227 | ParseDriver::~ParseDriver() { 228 | // This should be done by the parent, but it uses delete, not delete[]... 229 | delete[] yy_state_buf; 230 | yy_state_buf = NULL; 231 | 232 | if (yy_start_stack != NULL) { 233 | free(yy_start_stack); 234 | yy_start_stack = NULL; 235 | } 236 | } 237 | 238 | void ParseDriver::Error( 239 | const YYParser::location_type& loc, const std::string& msg) { 240 | errors_ << "ERROR: " << loc << ":" << msg << std::endl; 241 | num_errors_++; 242 | } 243 | 244 | void ParseDriver::Error(const std::string& msg) { 245 | errors_ << "ERROR: " << msg << std::endl; 246 | num_errors_++; 247 | } 248 | 249 | void ParseDriver::Fatal( 250 | const YYParser::location_type& loc, const std::string& msg) { 251 | Error(loc, msg); 252 | throw FatalParseError(); 253 | } 254 | 255 | void ParseDriver::LexerError(const char* msg) { 256 | Fatal(location_, msg); 257 | } 258 | 259 | void ParseDriver::Unput(char c) { 260 | assert(location_.end.column > 0); 261 | location_.end.column--; 262 | yyunput(c, yytext); 263 | } 264 | 265 | } // namespace t9 266 | /* END LEXER */ 267 | --------------------------------------------------------------------------------