Skip to content

Commit 181ce0c

Browse files
committed
First implementation
1 parent b9922f4 commit 181ce0c

File tree

12 files changed

+829
-0
lines changed

12 files changed

+829
-0
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
position.hh
2+
parser.cpp
3+
parser.hpp
4+
location.hh
5+
stack.hh
6+
scanner.cpp
7+
a.out

LICENCE.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2014 Krzysztof Narkiewicz <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
all:
2+
flex -o scanner.cpp scanner.l
3+
bison -o parser.cpp parser.y
4+
g++ -g main.cpp scanner.cpp parser.cpp interpreter.cpp command.cpp -o a.out
5+
6+
clean:
7+
rm -rf scanner.cpp
8+
rm -rf parser.cpp parser.hpp location.hh position.hh stack.hh
9+
rm -rf a.out

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#Flex & Bison LALR C++ example#
2+
3+
## What? ##
4+
5+
This is a not-so-crude example showing how to deploy *Flex* and *GNU Bison* in modern C++ programs. Example program provides simple commandline that parses function calls with list of arguments (unsigned ints only) and builds AST. AST is printed when parsing completes. See code comments for more details.
6+
7+
Features:
8+
9+
* Compatible with the good, old `C++03` for maximum portability.
10+
* Fully reentrant parser and lexer, C++ implementation.
11+
* Parser and lexer are in a customized namespace with custom class names.
12+
* Flex base class has a customized name; multiple different flex scanners in the binary are possible without a name conflict. Believe it or not, but even in the 21st century it is still a bit tricky with *Flex*.
13+
* Parser and scanner enclosed in a "driver" class (`Interpreter`)
14+
* Uses *Bison 3.0* token variant API (yay!).
15+
* Location tracking. Not perfect, but the core is there.
16+
17+
Once we overcome the abovementioned obstacles, the *Flex/GNU Bison* pair becomes quite pleasant to use in day to day work.
18+
19+
## Disclaimer ##
20+
21+
Haven't tested it on *MS Windows*. Please tell me if it works there... Do not forget to turn off `unistd.h` in options.
22+
23+
## Why bother? ##
24+
25+
Official *GNU Bison* example features C++ parser connected to primitive C-style lexer, which is probably not what you want most of the time. There is currently (2014) no easy way to find a true C++ example of elegant *Flex/Bison3* deployment. I really do not understand why a serious project like *Bison* provides such a poor user-experience for beginners.
26+
27+
##Yea, but still, why bother with old Flex/Bison?##
28+
29+
*ANTLR4* has been released without C++ support nor any estimation (last checked September 2014). The *Java* generator is premium quality though.
30+
31+
*ANTRL3* explicitly states that C++ support is total garbage and the mailing lists didn't make my impression any better.
32+
33+
*Flexc++* and *Bisonc++* are not that popular. I wasn't sure about portability either.
34+
35+
*Flex* and *GNU Bison* don't pull any dependencies and the code is (or at least is claimed to be) portable. By "portable" I mean it works in *Unix* universe and *Windows*, because the latter one is the only platform on the planet being notorious for catastrophically imbecilic design decisions (`cmd.exe`, `http:\\www.microsoft.com\backslash\fetish`, etc), causing endless, epic portability issues and developer's nightmares.
36+
37+
## Source organization ##
38+
39+
The main function creates the `Interpreter` object and calls `parse()`. `Scanner` and `Parser` are encapsulated in the `Interpreter`. By default the `Scanner` reads the standard input, but you can switch it using the provided `Interpreter` API and feed it with an arbitrary stream, such as `std::stringstream`.
40+
41+
## Building ##
42+
43+
Crude Makefile is provided - not much...
44+
45+
`make`
46+
47+
`./a.out`
48+
49+
`make clean`
50+
51+
## Legal mumbo-jumbo ##
52+
53+
The example code is MIT-licensed. The code generated by *Flex* and *Bison* has a separate license: Modified, non-viral GPL, which is safe to use. See the source code files.
54+
55+
## TODO ##
56+
57+
* some kind of template to deploy a complete scanner/parser stub in a project with an IDE wizard
58+
* namespace defined with preprocessor?
59+
60+
## Special thanks ##
61+
62+
* My girl - for late coffees and feeding me during deep coding sessions
63+
* *Flex* and *GNU Bison* folks - for focus on portability and years of maintenance
64+
* MIT folks - for *MIT License*
65+
* Me - for assembling this example
66+
67+
Enjoy!

command.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2014 Krzysztof Narkiewicz <[email protected]>
5+
*
6+
* Permission is hereby granted, free of charge, to any person
7+
* obtaining a copy of this software and associated documentation
8+
* files (the "Software"), to deal in the Software without
9+
* restriction, including without limitation the rights to use,
10+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the
12+
* Software is furnished to do so, subject to the following
13+
* conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be
16+
* included in all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25+
* OTHER DEALINGS IN THE SOFTWARE.
26+
*
27+
*/
28+
29+
#include "command.h"
30+
31+
#include <iostream>
32+
#include <sstream>
33+
34+
using namespace EzAquarii;
35+
using std::cout;
36+
using std::endl;
37+
38+
Command::Command(const std::string &name, const std::vector<uint64_t> arguments) :
39+
m_name(name),
40+
m_args(arguments)
41+
{
42+
}
43+
44+
Command::Command(const std::string &name) :
45+
m_name(name),
46+
m_args()
47+
{
48+
}
49+
50+
Command::Command() :
51+
m_name(),
52+
m_args()
53+
{
54+
}
55+
56+
Command::~Command()
57+
{
58+
}
59+
60+
std::string Command::str() const {
61+
std::stringstream ts;
62+
ts << "name = [" << m_name << "], ";
63+
ts << "arguments = [";
64+
65+
for(int i = 0; i < m_args.size(); i++) {
66+
ts << m_args[i];
67+
if(i < m_args.size() - 1) {
68+
ts << ", ";
69+
}
70+
}
71+
72+
ts << "]";
73+
return ts.str();
74+
}
75+
76+
std::string Command::name() const {
77+
return m_name;
78+
}

command.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2014 Krzysztof Narkiewicz <[email protected]>
5+
*
6+
* Permission is hereby granted, free of charge, to any person
7+
* obtaining a copy of this software and associated documentation
8+
* files (the "Software"), to deal in the Software without
9+
* restriction, including without limitation the rights to use,
10+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the
12+
* Software is furnished to do so, subject to the following
13+
* conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be
16+
* included in all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25+
* OTHER DEALINGS IN THE SOFTWARE.
26+
*
27+
*/
28+
29+
#ifndef COMMAND_H
30+
#define COMMAND_H
31+
32+
#include <string>
33+
#include <vector>
34+
#include <stdint.h>
35+
36+
namespace EzAquarii {
37+
38+
/**
39+
* AST node. If you can call it AST at all...
40+
* It keeps function name and a list of arguments.
41+
*/
42+
class Command
43+
{
44+
public:
45+
Command(const std::string &name, const std::vector<uint64_t> arguments);
46+
Command(const std::string &name);
47+
Command();
48+
~Command();
49+
50+
std::string str() const;
51+
std::string name() const;
52+
53+
private:
54+
std::string m_name;
55+
std::vector<uint64_t> m_args;
56+
};
57+
58+
}
59+
60+
#endif // COMMAND_H

interpreter.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2014 Krzysztof Narkiewicz <[email protected]>
5+
*
6+
* Permission is hereby granted, free of charge, to any person
7+
* obtaining a copy of this software and associated documentation
8+
* files (the "Software"), to deal in the Software without
9+
* restriction, including without limitation the rights to use,
10+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the
12+
* Software is furnished to do so, subject to the following
13+
* conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be
16+
* included in all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25+
* OTHER DEALINGS IN THE SOFTWARE.
26+
*
27+
*/
28+
29+
#include "interpreter.h"
30+
#include "command.h"
31+
32+
#include <sstream>
33+
#include <boost/concept_check.hpp>
34+
35+
using namespace EzAquarii;
36+
37+
Interpreter::Interpreter() :
38+
m_commands(),
39+
m_scanner(*this),
40+
m_parser(m_scanner, *this),
41+
m_location(0)
42+
{
43+
44+
}
45+
46+
int Interpreter::parse() {
47+
m_location = 0;
48+
return m_parser.parse();
49+
}
50+
51+
void Interpreter::clear() {
52+
m_location = 0;
53+
m_commands.clear();
54+
}
55+
56+
std::string Interpreter::str() const {
57+
std::stringstream s;
58+
s << "Interpreter: " << m_commands.size() << " commands received from command line." << endl;
59+
for(int i = 0; i < m_commands.size(); i++) {
60+
s << " * " << m_commands[i].str() << endl;
61+
}
62+
return s.str();
63+
}
64+
65+
void Interpreter::switchInputStream(std::istream *is) {
66+
m_scanner.switch_streams(is, NULL);
67+
m_commands.clear();
68+
}
69+
70+
void Interpreter::addCommand(const Command &cmd)
71+
{
72+
m_commands.push_back(cmd);
73+
}
74+
75+
void Interpreter::increaseLocation(unsigned int loc) {
76+
m_location += loc;
77+
cout << "increaseLocation(): " << loc << ", total = " << m_location << endl;
78+
}
79+
80+
unsigned int Interpreter::location() const {
81+
return m_location;
82+
}

0 commit comments

Comments
 (0)