Filed under:
Code

Lemon is a parser generator - a tool which takes a context-free grammar and converts it into code which can parse a file using that grammar. It’s a very useful tool, but can be a bit fiddly to get set up when building an app with Xcode. It’s fiddly because it’s not the grammar file which gets compiled into your app, but the code generated from it.

This post will describe how to integrate both the Lemon tool and the converting of the grammar into an Xcode build.

Sample Code

A sample project including the code from this post can be downloaded from GitHub.

Setup

You will need to add the two files required by Lemon to your project. These are lemon.c and lempar.c. The former is the generator itself and the latter is a template file for the generated code. These are under source control in the SQLite fossil repository.

Building the Lemon tool

Before we can do anything else, we need to build the Lemon tool itself. In this example, we will do it as part of building the demo app. To do this, select the project in the project navigator and add a new Run Script build phase. Drag this build phase to be the first item and enter the following command:

clang -o "${DERIVED_FILES_DIR}/lemon" "${PROJECT_DIR}/LemonDemo/lemon.c"

And add an entry to the output files table below with the text:

$(DERIVED_FILE_DIR)/lemon

Your new build phase should look like this:

Xcode build rule showing code

Now, each time you build your app, the lemon binary will be built along with it.

Creating the parser code from a grammar

Next, we have to tell Xcode how to compile the grammar files using the freshly-built tool. To do this, add a build rule to your Xcode project to build files with names matching *.lemon. In the custom script area, insert the following code:

// Copy the grammar and template files to an intermediate directory
cp "${INPUT_FILE_PATH}" "${DERIVED_FILES_DIR}"
cp "${PROJECT_DIR}/lempar.c" "${DERIVED_FILES_DIR}"

// Build the parser from the grammar
cd "${DERIVED_FILES_DIR}"
"${DERIVED_FILES_DIR}"/lemon "${DERIVED_FILES_DIR}/${INPUT_FILE_NAME}"

// Change the file extension to allow Objective-C code in the grammar
cp "${INPUT_FILE_BASE}.c" "${INPUT_FILE_BASE}.m"

This script copies the C template file and grammar to an intermediate folder and builds it using the lemon tool. It then copies the built file from a .c extension to .m so that you can use Objective-C code in your grammar file.

You will also need to enter the expected output files below the script. Here you should add the following entries:

$(DERIVED_FILES_DIR)/$(INPUT_FILE_BASE).h
$(DERIVED_FILES_DIR)/$(INPUT_FILE_BASE).m

This is an important step! The output files are those that will be included by Xcode when building your app. Your build rule should now look like this:

Xcode build phase showing code

Finished!

Now your project is ready to build *.lemon grammar files into a parser. As you can see, integrating generated code is not a difficult task, but one that needs a little care to make sure it works correctly. Just remember the steps in order:

  1. Build the tool
  2. Use the tool to build the parser from the grammar
  3. Use the parser in your app

If there is interest, I will follow this up with a post describing how to write a basic grammar to parse particular texts. If you want to take a peek ahead, there’s more detail in the sample code for this demo.