LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Blogs > astrogeek
User Name
Password

Notices


Rate this Entry

Alphanumeric Calculator: Flex Specification

Posted 10-01-2021 at 07:29 PM by astrogeek
Updated 10-07-2021 at 01:47 AM by astrogeek (Rev. 3 source)

This post is Part 3 of the Alphanumeric Calculator program group.

Note: This is Rev. 3 version and works with Rev. 3 Bison specification.

Copy the code below into a file named alphacalc.l in your build directory for this project where Makefile and alphacalc.y are located.

This is the specification file for a Flex generated lexical analyzer, also called a lexer or scanner.

A brief description of the file contents follows, but if you are not familiar with Flex or lexical analysis in general I encourage questions and further discussion, here or in the LQ Programming forum!

The file has three sections separated by lines which contain %% and nothing else.

The first section is the definitions section which may contain options, literal code blocks and other definitions. See info flex for all the details!

The second section is the rules section which consists of regular expressions and associated action code in curly braces, {...}, to be invoked when a pattern is matched. Flex builds a very efficient engine for recognizing patterns in the input stream based on these rules. Operation time is O(n), linear in proportion to input length and not affected by the number of rules because each character is tested only once. Flex generates this engine as C source which we tell it to place into a file named alphacalc.c. It obtains the list of tokens recognized by the parser, and a few other definitions from the Bison generated header file, alphacalc.tab.h, so the Flex specification must be processed after the Bison specification.

The third section is the user subroutines section and consists of C code which is copied verbatim into the resulting alphacalc.c source file. This project does not include any subroutines used by the lexer so this section is empty in this file.

Code:
/* Flex specification for alphanumeric calculator
   Rev. 3 Added SGN, COM, multi-line expressions \\\n
   (Works with Rev. 3 Bison specification)

   2021 Robert Allen, astrogeek:linuxquestions.org
   License: Love others as yourself, do unto others as you would have them do to you,
   WITHOUT REGARD TO ANY OTHER standard, law, order, license, command or authority.
   Period.

Flex does not have a pre-processor so we cannot easily control debug options at compile time
   from within the file, so our Makefile provides the method.
   Invoke make with DEBUG=1 to build with debug trace enabled.

   'info flex' is the manual.
*/

%option noyywrap yylineno case-insensitive
%option stack
%{
#include "alphacalc.tab.h"
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>

#define UNDEF_BUF_SIZE 16

extern char *filename;
extern int head;

/* Location support */
int yycolumn = 1;
#define YY_USER_ACTION yylloc.filename = filename; \
    yylloc.first_line = yylloc.last_line = yylineno; \
    yylloc.first_column = yycolumn; yylloc.last_column = yycolumn+yyleng-1; \
    yycolumn += yyleng;
%}

%x COMMENT

%%
   /* COMMENTS */
"/*" { yy_push_state(COMMENT); }
<COMMENT>{"*/" { yy_pop_state(); }
[^*\n]+ {/*Do nothing*/}
"*"[^/] {/*Do nothing*/}
\n { yycolumn=1; }
}
^#.*\n { yycolumn=1; if(head){ printf("%s", yytext); return END; }}

   /* OPERATORS and OPTIONS */
"help" { yylval.i=0; return HLP; }
"usage" { yylval.i=1; return HLP; }
"debug" { yylval.i=1; return DBG; }
"trace" { yylval.i=0; return DBG; }
"alpha" { yylval.i=0; return FMT; }
"numeric" { yylval.i=1; return FMT; }
"both" { yylval.i=2; return FMT; }
"quit" { return QUIT; }
"and" { return AND; }
"head"|"heading" { return COM; }
"plus"|"+" { return '+'; }
"minus"|"-" { return '-'; }
"times"|"*" { return '*'; }
"divided by"|"over"|"/" { return '/'; }
"negative" { yylval.i=-1; return SGN; }
"positive" { yylval.i=1; return SGN; }
"(" { return '('; }
")" { return ')'; }

   /* NUMBER NAMES */
"zero" { yylval.l=0; return ZERO; }
"one" { yylval.l=1; return ONES; }
"two" { yylval.l=2; return ONES; }
"three" { yylval.l=3; return ONES; }
"four" { yylval.l=4; return ONES; }
"five" { yylval.l=5; return ONES; }
"six" { yylval.l=6; return ONES; }
"seven" { yylval.l=7; return ONES; }
"eight" { yylval.l=8; return ONES; }
"nine" { yylval.l=9; return ONES; }

"ten" { yylval.l=10; return TEN; }
"eleven" { yylval.l=11; return TEENS; }
"twelve" { yylval.l=12; return TEENS; }
"thirteen" { yylval.l=13; return TEENS; }
"fourteen" { yylval.l=14; return TEENS; }
"fifteen" { yylval.l=15; return TEENS; }
"sixteen" { yylval.l=16; return TEENS; }
"seventeen" { yylval.l=17; return TEENS; }
"eighteen" { yylval.l=18; return TEENS; }
"nineteen" { yylval.l=19; return TEENS; }

"twenty" { yylval.l=20; return TENS; }
"thirty" { yylval.l=30; return TENS; }
"forty" { yylval.l=40; return TENS; }
"fifty" { yylval.l=50; return TENS; }
"sixty" { yylval.l=60; return TENS; }
"seventy" { yylval.l=70; return TENS; }
"eighty" { yylval.l=80; return TENS; }
"ninety" { yylval.l=90; return TENS; }

"hundred" { yylval.l=1e2; return M2; }
"thousand" { yylval.l=1e3; return M3; }
"million" { yylval.l=1e6; return M6; }
"billion" { yylval.l=1e9; return M9; }

   /* SYMBOLIC NUMBERS */
[+-]?[0-9]+ {
   errno = 0;
      yylval.l=strtoll(yytext,NULL,10);
   if(errno==0)
      return NUMB;
   return NUMERR;
   }

   /* WHITESPACE */
[ \t]+ {/*Eat up whitespace*/}
\\\n { yycolumn=1; /* Multi-line expressions */ }
\n { yycolumn=1; return END; }

. {/* Undefined, eat up to UNDEF_BUF_SIZE-1 non-space trailing chars and show the text */
   char intext[UNDEF_BUF_SIZE]={'\0'};
      intext[0]=yytext[0];
      int indx=0;
      while(indx<(UNDEF_BUF_SIZE - 1) && intext[indx] && !isspace(intext[indx]))
         {
         intext[++indx]=input();
         yylloc.last_column++;
         yycolumn++;
         }
      unput(intext[indx]);
      intext[indx]='\0';
      lyyerror(yylloc, LYY_ERROR_TAG, "Undefined input! %s", intext); return YYerror;
      }

%%
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 05:12 AM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration