Flex and Bison

Purpose of Flex and Bison

Flex and Bison allow for the generation of programs that process structured data. A prime example for such programs are interpreters or compilers of programming languages. Other applications are possible such as a loader for specific file formats.

Flex is a successor of lex. They are both lexer generators.

Bison is a successor of Yacc. They are both parser generators.

A lexer reads a string of characters and given rules, returns token matched from the character stream. Token are groups of characters. The rules applied to convert characters into token are defined by the programmer. The file ending .l is usually used for flex files.

A parser takes a stream of token and given rules, recognized constructs in the language it is supposed to parse. A parser could for example recognize function definitions or definitions of if-statements. Parts or rules or entire rules can be bound to actions. As soon as a rule is recognized, the action is executed. Actions could be code generation, for example assembler code could be output when a rule was parsed.

Usage of Flex and Bison

When compiling, the first step is to use the bison parser generator on the .y file. This will generate a .c and a .h file.

The second step is to use the flex lexer generator on the .l file. The .l file has to import the .h file that was generated by the bison run in the first step. The reason for importing that generated header is that the header defines constants for token that have to be returned by the generated lexer.

This means that first the grammar rules are processed and then after that the lexer rules are processed. This is kind of backwards. One would expect that first the token are defined and then the rules are build on top of the available token. The process is more or less backwards. You defined the rules using token and at that point you do not care how the token are defined. In the second step, when you know which token the grammar rules need, you define what the token look like by designing appropriate lexer rules.

Gotchas

On MacOS you have to link agains -ll instead of -lfl

On MacOS, your parser file has to define yyerror() and yylex()

%{
   #include <stdio.h>
   void yyerror(const char* msg) {
   	  printf("bla %s\n", msg);
      fprintf(stderr, "bli %s\n", msg);
   }
   int yylex();
%}

 

HTTP HTTPS GET Requests with Poco

The standard Poco GET example has one major deficit, I can only succesfully execute a GET request against a server that supports HTTP. Most servers do not provide their content using HTTP any more. Instead a HTTPS GET request has to be executed.

In order to adjust the Poco HTTP example to use HTTPS, follow the steps outlined in https://stackoverflow.com/questions/10875938/how-to-use-openssl-in-poco-c-library-correctly

The example below is not good code at all whatsoever but it shows how to use the HTTPSClientSession instead of the HTTPClientSession to leverage the HTTPS protocol instead of the HTTP protocol.

#include <iostream>

#include "Poco/MD5Engine.h"
#include "Poco/DigestStream.h"

#include "Poco/Net/HTTPClientSession.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/HTTPMessage.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/StreamCopier.h"
#include "Poco/Path.h"
#include "Poco/URI.h"
#include <Poco/Exception.h>

using namespace std;

using Poco::Net::HTTPClientSession;
using Poco::Net::HTTPSClientSession;
using Poco::Net::HTTPRequest;
using Poco::Net::HTTPResponse;
using Poco::Net::HTTPMessage;
using Poco::StreamCopier;
using Poco::Path;
using Poco::URI;
using Poco::Exception;

int main(int argc, char** argv) {

  try {

    std::cout << "Hello world2" << std::endl;

    //URI uri("https://www.google.de:80/index.html");
    //URI uri("https://www.play-hookey.com:80/htmltest/");
    //URI uri("http://www.brainjar.com:80/java/host/test.html");

    //http://us.imdb.com/M/title-exact?Toy%20Story%20(1995)

    //URI uri("http://us.imdb.com:80/Title?Toy%20Story%20(1995)");
    //URI uri("https://www.imdb.com:443/Title?Toy%20Story%20(1995)");
    //URI uri("https://www.imdb.com/find?q=Toy%20Story%20(1995)");
    URI uri("https://www.imdb.com/find?q=Se7en%20(1995)");

    //URI uri("https://www.imdb.com:443/find?q=Toy%20Story%20(1995)");
    //URI uri("https://www.imdb.com:443/find");
    //URI uri("https://143.204.95.231:443/find");
    //URI uri("https://www.imdb.com:443");
    //URI uri("https://www.imdb.com");
    //URI uri("www.imdb.com");

    //URI uri("https://stackoverflow.com/");

    //URI uri("https://github.com/");

    // prepare path
    string path(uri.getPathAndQuery());
    if (path.empty())
      path = "/";

    std::cout << "host " << uri.getHost() << " port " << uri.getPort()
        << " path " << path << std::endl;

    HTTPRequest request(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);

    // HTTP
    //HTTPClientSession session(uri.getHost(), uri.getPort());

    // HTTPS
    const Poco::Net::Context::Ptr context = new Poco::Net::Context(
        Poco::Net::Context::CLIENT_USE, "", "", "",
        Poco::Net::Context::VERIFY_NONE, 9, false,
        "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
    HTTPSClientSession session(uri.getHost(), uri.getPort(), context);

    std::cout << "session.sendRequest" << std::endl;
    session.sendRequest(request);

    std::cout << "session.receiveResponse" << std::endl;

    HTTPResponse response;
    std::istream& rs = session.receiveResponse(response);

    std::cout << "session.getStatus" << std::endl;
    std::cout << response.getStatus() << " " << response.getReason()
        << std::endl;

    //StreamCopier::copyStream(rs, std::cout);

    std::string responseAsString(std::istreambuf_iterator<char>(rs), { });

  } catch (Exception &ex) {
    std::cerr << ex.displayText() << std::endl;
    return -1;
  }

  return 0;
}

 

Conan Package Manager for C++

https://docs.conan.io/en/latest/getting_started.html contains a good introduction to Conan.

Installing Conen on MacOS can be done via brew:

brew update
brew install conan

Conan is controlled by a file called conanfile.txt. It is comparable to a maven pom or the package.json file for the node package manager.

The conanfile.txt from the tutorial that works with CMake is duplicated below

[requires]
Poco/1.9.0@pocoproject/stable

[generators]
cmake

You can now execute conan install in the folder that contains the conanfile.txt to exceute Conan. It will install all dependencies and call all generators listed in the conanfile.txt.

If Conan fails to download precompiled binaries, sometimes it is possible to tell conan to build the depencencies from code:

conan install Poco/1.9.0@pocoproject/stable --build missing

To use Conan in combination with CMake, the conanfile.txt has to create a conanbuildinfo.cmake file using a generator for CMake. That file is then used from within CMake’s CMakeLists.txt file. When CMake builds the project, it is able to call Conan.

A CMakeLists.txt file that imports the generated conanbuildinfo.cmake is given below:

cmake_minimum_required (VERSION 2.6)

project (PocoTest)

add_definitions("-std=c++11")

include(${PROJECT_SOURCE_DIR}/build/conanbuildinfo.cmake)
conan_basic_setup()

add_executable(PocoTest PocoTest.cpp)
target_link_libraries(PocoTest ${CONAN_LIBS})

I think the workflow now is, whenever you need a new library in your project, add the dependency to Conans conanfile.txt. Then call conan install so Conan can download and install the new dependency and also generates an updated conanbuildinfo.cmake for CMake. Then build your project using CMake to include the newly provided dependencies.

CMake

Have a CMakeLists.txt file in each directory that
contains project source code. The root folder of all the
directories containing CMakeLists.txt files is referred
to as the source directory.

The source directory along with the binary directory
constitute the set of folders that CMake performs builds
in. A out-of-source build is one where CMake is reading
from the source directory and writing artefacts to the
binary directory. This is the default. By default CMake
will not write into the source directory, only read from
it. A in-source build is where CMake is configured to
write artifacts into the source directory, in other words
where source and binary directory are the same.

out-of-source builds are easier to maintain, because by
checking in the source directory to a version control
system and leaving the binary directory unversioned,
you are sure to not commit artifacts. Also you can
erase the binary directory and clean your project that
way.

CMakeLists.txt files contain one or more CMake commands

A command has the syntax: command (args…) where
command is the name of a command and args is a white-
space separated list of arguments. (Arguments with
embedded white-space should be double quoted).
Commands are also used for controlling the program flow
if() else() endif()

Variables are defined using the ${VAR} syntax.
Assigning a value is done using set(Foo a b c) which
sets the variable Foo to the list of values a b and c.
Using a variable: command(${Foo}) which is equivalent to
command(a b c) if Foo has the values a b c set.

Environment variables can be used: $ENV{VAR}

Building from the command line:
CMake offers the –build option, which is described as a
convenience that allows you to build your project from the
command line even if this requires launching an IDE.
The syntax is:
cmake –build <dir> [options] [– [native-options]]
cmake –build . — -v
will build in the current working directory and pass the
parameter -v to the underlying build tool.

Open Questions

Can I build with CMake?


Q: If CMake is a tool to generate build configurations
for different platforms, why can eclipse use cmake to
directly build a binary for my project?
A: CMake offers the –build option, which is described as a
convenience that allows you to build your project from the
command line even if this requires launching an IDE

Where does the build folder and the contained folders
in my EclipseCDT project come from?


Q: When looking at my CMake project in EclipseCDT, it
has a build folder and a lot of folders and files below
it, where do these folders come from?
A: ???

Eclipse CDT C++ CMake on Mac

Using Eclipse CDT on mac along with the g++ compiler is a very good option if you know your Eclipse hotkeys from programming in Java for example or if you are looking for an alternative to XCode.

Eclipse CDT allows you to create CMake projects. This post sums up the traps I got caught up in before getting everything to work in the hopes it will help others to not make the errors I made.

On your Mac, first install cmake and ninja

brew update
brew install cmake
brew install cask cmake
brew install ninja

If the brew commands fail, try repeating them, this sometimes fixes install issues.

Next, start Eclipse CDT from the console instead of from the finder (CMD + space). To start Eclipse CDT from a console, execute the command

open -a EclipseCDT.app

Opening Eclipse CDT from the finder will not add /usr/local/bin to Eclipse’s Path! Opening Eclipse CDT from the command line will add /usr/local/bin to Eclipse’s Path. /usr/local/bin has to be part of the PATH as only then can Eclipse CDT execute ninja and cmake. This is summed up in the post: https://bugs.eclipse.org/bugs/show_bug.cgi?id=532419

You are now able to create a new C/C++ CMake project from within eclipse, clean it, build it and run the executable.

Python Cheatsheet

ToString() for Classes
class ObjModel(object):

    def __init__(self):
        self.vertices = []

    def __str__(self):
        return str(self.vertices[5][0])
Enumerations
class ObjFaceType(Enum):
    TRIANGLE = 1
    QUADRILATERAL = 2
    UNKNOWN = 999
Create Enumeration-Value from Integer
detectedFaceType = ObjFaceType(999)
Compare Value to Enumeration
if (currentFaceType == ObjFaceType.UNKNOWN):
Switch over Enumeration-Values

There is no such feature!

Create a new Class
# as a .obj file contains several objects, the ObjModelContainer stores all those objects
class ObjModelContainer(object):

    def __init__(self):
        self.objects = []
Create a Instance of a Class
objAdapter = ObjAdapter()

 

OpenGL on MacOS (C / C++)

Disclaimer

OpenGL is deprecated on MacOS in favor of Metal. If you still want to use OpenGL, it is still possible to compile applications. Also as another disclaimer, the examples I post use deprecated OpenGL constructs. OpenGL changed over the time and added new features whereas older features were depreacted. As I am learning myself, I am using deprecated features until I get comfortable with the newer stuff. So be aware and inform yourself about the most current OpenGL features.

Compiling OpenGL applications on MacOS

Reading this post, it is necessary to import OpenGL headers from specific folders on MacOS instead of the default paths used on Windows and Linux.

#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glut.h>
#endif

The command line for compiling is:

g++ blender.c -framework OpenGL -framework GLUT

You will get a lot of warnings, because all OpenGL calls are deprecated but the compiler should generate a a.out nevertheless, which you can execute using

./a.out

Resolution on Retina-Displays

Running a glut application on a retina display displays in a real low resolution. I did not figure out the solution for this but there are some pages explaining solutions:

https://www.opengl.org/discussion_boards/showthread.php/178916-Using-the-retina-display-on-a-macbook-pro

http://iihm.imag.fr/blanch/software/glut-macosx/

Installing Python 3 on MacOS using homebrew

MacOS Systems come with python 2 preinstalled. Installing python 3 can be done using homebrew.

brew install python3
brew postinstall python3

Check for success using

python3 --version
pip3 -V

If brew complains that python3 is installed but not linked, use

brew link python

For me, linking failed with:

Warning: python 3.7.2 is already installed, it's just not linked
You can use `brew link python` to link this version.
MacBook-Pro:~ user$ brew link python
Linking /usr/local/Cellar/python/3.7.2... Error: Permission denied @ dir_s_mkdir - /usr/local/Frameworks

If the linking fails due to permission problems, you should read this thread.

They suggest a solution that entails creating and setting permissions on a folder:

sudo mkdir /usr/local/Frameworks

sudo chown $(whoami):admin /usr/local/Frameworks

Now try linking again, for me the link finally worked and python was available.

brew link python

python3 --version

Installing virtualenv

pip3 install virtualenv

 

Using virtualenv

Creation of a virtual environment:

$ virtualenv -p python3 <desired-path>

e.g. virtualenv -p python3 /home/user/dev/python/myproject/myenv

Activate the virtualenv:

$ source <desired-path>/bin/activate

e.g. source /home/user/dev/python/myproject/myenv/bin/activate

Deactivate the virtualenv:

$ deactivate