Installing the new Visual Studio 2012, I was surprised to find no "C" project template, only C++. Googling yielded no C-only templates and few concrete examples; it seems C has fallen to the wayside... even though the compiler still supports it. So a method of creating a C project from the C++ template is provided.
Also discussed is how to setup this project to use a Windows version of Flex and Bison - tools for lexical analysis and parsing of data streams.
Lex and Yacc originated in the UNIX world long ago. Yacc stands for 'yet another compiler compiler', and Lex is a 'lexical analyzer'. Lex reads a file or data stream and breaks it up into its component pieces, which it calls tokens. Tokens may be numbers, keywords, strings, punctuation, etc. Yacc commonly receives this stream of tokens, structures them according to rules, then looks for matching patterns. If a match is found, some action is taken. These two tools together make it possible to parse an input stream and act on it, much more cleanly and effectively than writing hundreds of lines of traditional C code. The Lex and Bison syntax is very powerful and very compact.
Today, the GNU equivalents of Lex and Yacc are called Flex and Bison (heh!) They are still only Unix platform tools, however. Nothing quite like these have ever made it to the Win32 world. A few ports of these were made over the years, but they required lots of GNU support libraries and were not updated regularly at all. (The last Flex port I found is almost a decade old!) Of course, it was too old to work with the example used.
But a few developers over at SourceForge have created a package called WinFlexBison. This is a compact, all-inclusive port of modern Flex and Bison for Win32, and is maintained regularly. This is the package we will use.
As a side note, WinFlexBison can output C, C++, and Java code, but only C is used here.
Creating a Win32 "C" Project in VS2012
To create a Win32 "C" project in Visual Studio 2012:
1. Create a new project. Pick Win32 C++ Console. Give it a descriptive name. Next.
2. Uncheck the box for "use precompiled headers" and check the box for "create empty project." Click Finish.
3. Right-click "Source Files", click "Add" then "New Item." Call it main.c. Click it and copy this text into it:
printf("Press ENTER to close. ");
4. Right-click the main project in the solution explorer at left, and choose Properties, C/C++, All Options, and set "Compile As" to "C Code."
5. Hit F5 to compile and debug. There's your "C" project!
Using Flex and Bison in Windows
To use Flex and Bison in windows,
1. Get WinFlexBison from http://sourceforge.net/projects/winflexbison/ and extract somewhere meaningful, then add that path to the system path. If you need help with the system path, see this and this. Close any command prompts.
2. Create these new files in the project: Expression.c/.h, Lexer.l/.c/.h, Parser.y/.c/.h
3. Copy the file data from http://en.wikipedia.org/wiki/GNU_bison into these files (some will remain empty.) Incorporate the pause code from earlier into the end of the real main(). Be sure to SAVE all of these files as data is entered, we will need it for the next step.
4. Open a command prompt, navigate to your .Y and .L files, and run these commands:
No error messages from Flex or Bison? Good. Can also test other settings this way. This example liked having the --wincompat option turned on.
5. Try to build the project. It will probably reveal a few warnings. You will need to work through these in a minute.
Now to automate the building of the .l and .y files:
1. Right-click Parser.y -> Properties -> "Item Type" to "Custom Build Tool."
2. Click "Custom Build Tool" on the left, and type "c:\your-path-to-winflexbison\win_bison parser.y" as the command, substituting the real path.
3. Change the description to "BISON Custom Build Tool."
4. Set "Outputs" to "parser.h,parser.c"
Repeat for Lexer.l, but with "yourpath\win_flex --wincompat lexer.l" as the command, etc.
Hit F5... Voila! Now go get them bugs. :) You should end up with this:
Points of Interest
If you follow this guide verbatim (and the example at Wikipedia hasn't changed), there should be two "errors." One, "yyerror" will be defined twice. This is because this function appears in both Lexer.l and Parser.y. The solution is to change one of them to just:
int yyerror(SExpression **expression, yyscan_t scanner, const char *msg);
The other issue was a main.c(24): warning C4090: 'function' : different 'const' qualifiers
. That's rather vague, but looking at that line of code, this simple change fixes it:
SExpression *getAST(char *expr)
Revision 1.0 on 2013.9.11