📚 LinuxDocs
Topics:
All Pages8021X HOWTOACP ModemACPI HOWTOADSL Bandwidth Man..ATA RAID HOWTOATM Linux HOWTOAX25 HOWTOAccessibility Dev ..Accessibility HOWTOAdv Bash Scr HOWTOAdv Routing HOWTOAntares RAID sparc..Apache Compile HOWTOApache WebDAV LDAP..Assembly HOWTOAstronomy HOWTOAthlon Powersaving..Authentication Gat..Autodir HOWTOAviation HOWTOAvr Microcontrolle..BRIDGE STP HOWTOBTTVBackspaceDeleteBandwidth Limiting..Bangla HOWTOBash Prompt HOWTOBattery PoweredBelarusian HOWTOBelgian HOWTOBeowulf HOWTOBocaBogoMipsBootdisk HOWTOBridgeC++ dlopenC C++Beautifier HO..C editing with VIM..CDROM HOWTOCDServer HOWTOCable ModemCaudium HOWTOClone HOWTOCompaq Remote Insi..Compaq T1500 HOWTOConexant+Rockwell ..Cryptoloop HOWTODB2 HOWTODHCPDSL HOWTODVD Playback HOWTODebian Binary Pack..Debian JigdoDebian and Windows..Disk Encryption HO..Disk on Chip HOWTODocBook Demystific..DocBook InstallDocBook OpenJade S..Ecology HOWTOEmacspeak HOWTOEncourage Women Li..Encrypted Root Fil..Euro Char SupportEvent HOWTOFedora Multimedia ..Finnish HOWTOFirewall PiercingFlash Memory HOWTOFont HOWTOFramebuffer HOWTOGCC HOWTOGIS GRASSGlibc Install HOWTOHOWTO HOWTOHOWTO INDEXHP HOWTOHandspring VisorHard Disk UpgradeHardware HOWTOHighQuality Apps H..Home Electrical Co..IBM7248 HOWTOIO Perf HOWTOIP AliasIP Masquerade HOWTOIRCImplement Sys Call..Indic Fonts HOWTOInfrared HOWTOIngresII HOWTOInstall StrategiesInstallation HOWTOInstallfest HOWTOIntkeybItalian HOWTOJabber Server Farm..JavaStation HOWTOKerberos Infrastru..Kernel HOWTOKerneldKodak Digitalcam H..LDAP HOWTOLDP Reviewer HOWTOLILO crash rescue ..LVM HOWTOLeased LineLegoLinksys Blue Box R..Linux+Win95Linux+Win9x+Grub H..Linux+Windows HOWTOLinux Complete Bac..Linux Crash HOWTOLinux Gamers HOWTOLinux Modem SharingLinux Promise RAID..Linux i386 Boot Co..LinuxGL QuakeWorld..Lotus DominoR5MILO HOWTOMMBase Inst HOWTOMP3 CD BurningMail User HOWTOMajordomo MajorCoo..Man PageMasquerading Simpl..Medicine HOWTOMindTerm SSH HOWTOMobile IPv6 HOWTOMock MainframeModule HOWTOModulesMotorola Surfboard..Mozilla OptimizationMulti Distro DevNCURSES Programmin..NFS HOWTONFS Root Client mi..NIS HOWTONetMeeting HOWTONetwork boot HOWTONvidia OpenGL Conf..OLSR IPv6 HOWTOOnline Troubleshoo..Oracle 9i Fedora 3..PA RISC Linux Boot..PCTel MicroModem C..PHP Nuke HOWTOPPP HOWTOPagerPalmOS HOWTOPartitionPartition Mass Sto..Partition Mass Sto..Partition RescuePine ExchangePortSlavePost Installation ..Postfix Cyrus Web ..Pre Installation C..Print2WinPrinting HOWTOProcess AccountingProgram Library HO..Proxy ARP SubnetQmail ClamAV HOWTOQmail VMailMgr Cou..Querying libiptc H..RPM HOWTOReading List HOWTORedHat CD HOWTOReliance HOWTORemote BridgingRemote Serial Cons..SCSI 2.4 HOWTOSCSI Generic HOWTOSLIP PPP EmulatorSRM HOWTOSSL Certificates H..Scanner HOWTOScientific Computi..Scripting GUI TclTkSecure CVS PserverSecure Programs HO..Security HOWTOSecurity Quickstar..Security Quickstar..Serial Laplink HOWTOSerial Programming..Slovak HOWTOSmall MemorySmart Card HOWTOSoftware Proj Mgmt..Software Release P..Sound HOWTOSpam Filtering for..Speech Recognition..SquashFS HOWTOSybase ASA HOWTOSybase ASE HOWTOSybase PHP ApacheTCP Keepalive HOWTOTamil Linux HOWTOTimePrecision HOWTOTimeSys Linux Inst..Token RingTraffic Control HO..Traffic Control tc..UPS HOWTOUnix Hardware Buye..Unix and Internet ..UpgradeUsenet News HOWTOUser Authenticatio..VB6 to TclVMS to Linux HOWTOVPN HOWTOValgrind HOWTOVideoLAN HOWTOVim HOWTOVirtual WebWebcam HOWTOWikiText HOWTOWindows Newsreader..Wireless Link sys ..Wireless Sync HOWTOXDM XtermXDMCP HOWTOXFree Local multi ..XFree86 HOWTOXFree86 R200XFree86 Second MouseXFree86 Video Timi..XML RPC HOWTOXWindow Overview H..XWindow User HOWTOXinerama HOWTOXterminalsHtml singleI810 HOWTOLibdc1394 HOWTOOpenMosix HOWTOPhhttpd HOWTOPpp sshText
Next Previous Contents

3. Lex

The program Lex generates a so called `Lexer'. This is a function that takes a stream of characters as its input, and whenever it sees a group of characters that match a key, takes a certain action. A very simple example: [Fedora Modules]

%{
#include <stdio.h>
%}

%%
stop    printf("Stop command received\n");
start   printf("Start command received\n");
%%

The first section, in between the %{ and %} pair is included directly in the output program. We need this, because we use printf later on, which is defined in stdio.h. [Library: SSH]

Sections are separated using '%%', so the first line of the second section starts with the 'stop' key. Whenever the 'stop' key is encountered in the input, the rest of the line (a printf() call) is executed.

Besides 'stop', we've also defined 'start', which otherwise does mostly the same.

We terminate the code section with '%%' again.

To compile Example 1, do this:

lex example1.l
cc lex.yy.c -o example1 -ll

NOTE: If you are using flex, instead of lex, you may have to change '-ll' to '-lfl' in the compilation scripts. RedHat 6.x and SuSE need this, even when you invoke 'flex' as 'lex'!

This will generate the file 'example1'. If you run it, it waits for you to type some input. Whenever you type something that is not matched by any of the defined keys (ie, 'stop' and 'start') it's output again. If you enter 'stop' it will output 'Stop command received';

Terminate with a EOF (^D).

You may wonder how the program runs, as we didn't define a main() function. This function is defined for you in libl (liblex) which we compiled in with the -ll command.

3.1 Regular expressions in matches

This example wasn't very useful in itself, and our next one won't be either. It will however show how to use regular expressions in Lex, which are massively useful later on.

Example 2:

%{
#include <stdio.h>
%}

%%
[0123456789]+           printf("NUMBER\n");
[a-zA-Z][a-zA-Z0-9]*    printf("WORD\n");
%%

This Lex file describes two kinds of matches (tokens): WORDs and NUMBERs. Regular expressions can be pretty daunting but with only a little work it is easy to understand them. Let's examine the NUMBER match:

[0123456789]+

This says: a sequence of one or more characters from the group 0123456789. We could also have written it shorter as: .:: telescope.ac ::.

[0-9]+

Now, the WORD match is somewhat more involved:

[a-zA-Z][a-zA-Z0-9]*

The first part matches 1 and only 1 character that is between 'a' and 'z', or between 'A' and 'Z'. In other words, a letter. This initial letter then needs to be followed by zero or more characters which are either a letter or a digit. Why use an asterisk here? The '+' signifies 1 or more matches, but a WORD might very well consist of only one character, which we've already matched. So the second part may have zero matches, so we write a '*'.

This way, we've mimicked the behaviour of many programming languages which demand that a variable name *must* start with a letter, but can contain digits afterwards. In other words, 'temperature1' is a valid name, but '1temperature' is not.

Try compiling Example 2, lust like Example 1, and feed it some text. Here is a sample session:

$ ./example2
foo
WORD

bar
WORD

123
NUMBER

bar123
WORD

123bar
NUMBER
WORD

You may also be wondering where all this whitespace is coming from in the output. The reason is simple: it was in the input, and we don't match on it anywhere, so it gets output again. .:: iawbs.com ::. .:: colab.research.google.com ::.

The Flex manpage documents its regular expressions in detail. Many people feel that the perl regular expression manpage (perlre) is also very useful, although Flex does not implement everything perl does.

Make sure that you do not create zero length matches like '[0-9]*' - your lexer might get confused and start matching empty strings repeatedly. .:: podcasts.apple.com ::.

3.2 A more complicated example for a C like syntax

Let's say we want to parse a file that looks like this: .:: podcasts.apple.com ::.

logging {
        category lame-servers { null; };
        category cname { null; };
};

zone "." {
        type hint;
        file "/etc/bind/db.root";
};

We clearly see a number of categories (tokens) in this file:

The corresponding Lex file is Example 3:

%{
#include <stdio.h>
%}

%%
[a-zA-Z][a-zA-Z0-9]*    printf("WORD ");
[a-zA-Z0-9\/.-]+        printf("FILENAME ");
\"                      printf("QUOTE ");
\{                      printf("OBRACE ");
\}                      printf("EBRACE ");
;                       printf("SEMICOLON ");
\n                      printf("\n");
[ \t]+                  /* ignore whitespace */;
%%

When we feed our file to the program this Lex file generates (using example3.compile), we get:

WORD OBRACE 
WORD FILENAME OBRACE WORD SEMICOLON EBRACE SEMICOLON 
WORD WORD OBRACE WORD SEMICOLON EBRACE SEMICOLON 
EBRACE SEMICOLON 

WORD QUOTE FILENAME QUOTE OBRACE 
WORD WORD SEMICOLON 
WORD QUOTE FILENAME QUOTE SEMICOLON 
EBRACE SEMICOLON 

When compared with the configuration file mentioned above, it is clear that we have neatly 'Tokenized' it. Each part of the configuration file has been matched, and converted into a token.

And this is exactly what we need to put YACC to good use.

3.3 What we've seen

We've seen that Lex is able to read arbitrary input, and determine what each part of the input is. This is called 'Tokenizing'.


Next Previous Contents

Share or Research:

Share on FB Post to X LinkedIn 🤖 Ask AI about this