This is the regular grammar represented by the finite state machine that we worked out for recoginising floating point numbers as commonly expressed in programming languages X Y Z means an X followed by a Y followed by a Z X | Y | Z means an X or a Y or a Z, but only one { X } means the enclosed thing is optional ( X ) is just normal parentheses, to make grouping clear X * means any number (including zero) of Xs X + means any number, at least one, of Xs d represents an decimal digit . represents itself, a dot e represents a choice of either the letter e or the letter E s represents either the character '+' or the character '-' # represents the end of the input. This is almost never used, except occasionally when things need to be made extra clear sequencing, X Y Z, has a higher priority than choice, X | Y | Z. {+|-} (d* . d+ | d+ . d* | d+) {e {+|-} d+} # Unfortunately, that is Non-Deterministic. After the optional + or - at the beginning, there is a choice of three things, but they all begin with a digit, so a program based on this would not be able to tell which path to follow. {+|-} (. d+ | d+ {. d*}) {e {+|-} d+} # It wasn't difficult to fix, but the result is much less clear. That form is only good for very simple cases. For anything more it gets out of hand very quickly. An alternative form, often called a production system is easire to handle: ::= d | . | s ::= d | . | e | # ::= d ::= d | . ::= # | d | s ::= d | e | # ::= s | d ::= d ::= d | # is called a non-terminal symbol, it will appear in a definition others are terminal symbols, they must appear as they are in the input ::= B means is defined to be, or can by replaced by, B Only a single terminal can be to the left of ::= To the right must be either a single thing or a choice of things, where each "thing" may only be a sequence of zero or more terminal symbols, optionally followed by a single non-terminal symbol or nothing at all "nothing at all" is often given its own symbol just for readability. It is usually an O with a diagonal line through it (like for an empty set) or a lower case greek epsilon. If your grammar follows either of those forms, or even a combination of them, it is guaranteed that it can be perfectly recognised by a finite state machine. And any finite state machine can be represented by a grammar that follows these rules. In a well designd programming language, all of the lexemes, the individual symbols that make up a program can be defined by a regular grammar. This means that a program to do the recognition can be created robotically, it is just a while loop containing a switch containing some ifs. Using the second version of the grammar, and using the numbers 1 to 8 to represent the non-terminals to , and 0 for , 999 for successful completion, and 666 for rejection we get this. I'm assuming that white space separates symbols, not a generally safe assumption, but we need something. state = 0 while (true) { ch = getchar(); switch (state != 999 && state != 666) { case 0: if (isdigit(ch)) state = 1; else if (ch == '.') state = 2; else if (ch == '+' || ch == '-') state = 3; else state = 666; case 1: if (isdigit(ch)) state = 1; else if (ch == '.') state = 4; else if (ch == 'e' || ch == 'E') state = 6; else if (isspace(ch)) state = 999; else state = 666; case 2: if (isdigit(d)) state = 5; else state = 666; case 3: if (isdigit(ch)) state = 1; else if (ch == '.') state = 2; else state = 666; case 4: if (isdigit(ch)) state = 5; else if (ch == '+' || ch == '-') state = 7; else if (isspace(ch)) state = 999; else state = 666; case 5: if (isdigit(ch)) state = 5; else if (ch == 'e' || ch == 'E') state = 6; else if (isspace(ch)) state = 999; else state = 666; case 6: if (ch == '+' || ch == '-') state = 7; else if (isdigit(ch)) state = 8; else state = 666; case 7: if (isdigit(ch)) state = 8; else state = 666; case 8: if (isdigit(ch)) state = 8; else if (isspace(ch)) state = 999; else state = 666; } } Following the single line form can get quite complicated: {+|-} (. d+ | d+ {. d*}) {e {+|-} d+} ch = getchar(); if (ch == '+' || ch == '-') ch = getchar(); if (ch == '.') { ch = getchar(); if (! isdigit(ch)) return REJECT; while (isdigit(ch)) ch = getchar(); } else if (isdigit(ch)) { while (isdigit(ch)) ch = getchar(); if (ch == '.') { ch = getchar(); while (isdigit(ch)) ch = getchar(); } } else return REJECT; if (ch == 'e' || ch == 'E') { ch = getchar(); if (ch == '+' || ch == '-') ch = getchar(); if (! isdigit(ch)) return REJECT; while (isdigit(ch)) ch = getchar(); } return ACCEPT;