spinoza1111 said:
<snip>
But I think you messed up the grammar...but not the code.
expr -> term { [+-] term }
doesn't parse 1+1+1.
The {} is a very common notation. I agree that [+-] is not usual, but were
you at all puzzled by what the notation meant? It is obviously
borrowed from regular expressions.
OK, that's correct: [+-] is "the set of characters including plus and
minus" where one character is chosen from the set. But I shouldn't
have to do the work of expressing things clearly on your behalf in
English.
Nor should regular expression notation be mixed into BNF unless
absolutely necessary.
Most extended grammar notations use very similar nation to that used
in regular expressions. I don't see a problem with that.
But in neither notation do curley braces imply iteration and as far as
I can see you need iteration to parse 1+1+1. What am I missing, dear
Ben?
That {} denotes repetition in all the forms of EBNF that I have seen.
They both look wrong (and note that unlike some of the thugs and
twerps here I don't infer your global ignorance). Period ordinarily
means end of string (which is needed as I have said when you do not
lookahead to balance parentheses)....not iteration.
In Wirth's version of EBNF (note the E) . ends the production. ()s
indicate grouping and | alternation (as in most regular expression
syntax) and {} repetition zero or more times.
The second is in particular absurd. If by | you mean BNF or, then
you're saying that an expr may start with a plus sign. If you add
unary minus it may but I do not believe this was your intent.
No, I missed the term that starts each alternation:
expr = term | term { "+" , term } | term { "-" , term } ;
Where () can't be used to group and alternation, the alternatives get
more complex. The point being that in both Wirth's EBNF and in plain
EBNF {} means repetition.
I think
you either have a private BNF notation, Bacarisse Normal Form, or you
don't know how to use BNF at all.
Here is the correct BNF as far as I can tell:
expr := addFactor
expr := addFactor ( [+-] addFactor ) *
You keep saying BNF but all these are extended notations. BNF used
As a favor to you I use the square bracket set notation and instead of
square brackets for optional sequence I've split the production into
two parts, using round parentheses to group and asterisk to iterate.
Your notation -- specifically adding * after an optional item -- is
not common. I've not seen it in any text. Some EBNFs do use * but as
a operator applied to any element. Applying it to something optional
is redundant.
<snip>
Here is the latest C version, based on my grammar. The issues you
raised have been fixed, and documentation has been added. The code
list is followed by the output.
The code list tabbing may be incorrect.
// ***************************************************************
// * *
// * infix2PolishC Infix to Polish notation using a grammar *
// * *
// * *
// * This application converts infix to Polish notation using a *
// * simple grammar and two different implementations. It also *
// * contains testing and timing facilities. For more *
// * information, see the readme.TXT file in this project. *
// * *
// * *
// * C H A N G E R E C O R D --------------------------------- *
// * DATE PROGRAMMER DESCRIPTION OF CHANGE *
// * -------- --------- --------------------------------- *
// * 11 01 09 Nilges Version 1 *
// * *
// * 11 03 09 Nilges Version 2 *
// * ANON 1. Commenting added DONE *
// * 2. Routine index added with *
// * forward definitions DONE *
// * 3. Expected/actual cleanup DONE *
// * 4. Bug? Seems to convert Polish *
// * expression to value of first *
// * token without complaint *
// * FIXED *
// * 5. Minor bug: extra spaces in *
// * polish expression FIXED *
// * 6. Bugs as found by anon *
// * 8.1 1) FIXED *
// * 8.2 (((1)))) FIXED *
// * 7. Predetermine malloc using *
// * number of symbols other than *
// * parentheses and white space *
// * *
// * I S S U E S ----------------------------------------------- *
// * DATE POSTER DESCRIPTION AND RESOLUTION *
// * -------- --------- --------------------------------- *
// * 11 03 09 Nilges Version 3 plan *
// * 1. Random expressions *
// * 2. Integrate in GUI with C sharp,*
// * versions from Gene & anon *
// * 3. Predetermine malloc using *
// * number of symbols other than *
// * parentheses and white space *
// * *
// ***************************************************************
#include <stdio.H>
#include <stdlib.H>
// ***** Constants ***********************************************
#define MAX_POLISH_LENGTH 100
#define ABOUT_INFO \
"This application converts infix to Polish notation using a simple
grammar and two different implementations. It also contains testing
and timing facilities."
// ***** Macros **************************************************
// --- Pass over white space
#define SKIP_WHITE_SPACE(s, i, e) \
{ for(; (i) <= (e) && (s)[(i)] == ' '; (i)++ ); }
// ***** Function index ******************************************
#define ADDFACTOR \
int addFactor(char *strInfix, \
char *strPolish, \
int *intPtrIndex, \
int intEnd)
ADDFACTOR;
#define ERRORHANDLER \
int errorHandler(char *strMessage)
ERRORHANDLER;
#define ERRORHANDLERSYNTAX \
int errorHandlerSyntax(int intIndex, \
char *strMessage, \
char *strInfix)
ERRORHANDLERSYNTAX;
#define EXPRESSION \
int expression(char *strInfix, \
char *strPolish, \
int *intPtrIndex, \
int intEnd)
EXPRESSION;
#define INFIX2POLISH \
char *infix2Polish(char *strInfix)
INFIX2POLISH;
#define MAIN \
int main(int intArgCount, char **strArgs)
MAIN;
#define MULFACTOR \
int mulFactor(char *strInfix, \
char *strPolish, \
int *intPtrIndex, \
int intEnd)
MULFACTOR;
#define STRINGAPPENDCHAR \
int stringAppendChar(char *strInstring, \
char chrNew, \
int intMaxLength, \
int intSpaceBefore)
STRINGAPPENDCHAR;
#define STRINGLENGTH \
int stringLength(char *strInstring)
STRINGLENGTH;
#define TESTCASE \
void testCase(char *strInfix, char *strExpected)
TESTCASE;
#define TESTER \
void tester()
TESTER;
// ***** Functions ***********************************************
// ---------------------------------------------------------------
// Command line handler
//
// int main(int intArgCount, char **strArgs)
//
MAIN
{
tester();
return;
}
// ---------------------------------------------------------------
// Parse add factor
//
// int addFactor(char *strInfix,
// char *strPolish,
// int *intPtrIndex,
// int intEnd)
//
// addFactor = mulFactor [ *|/ mulFactor ]
//
ADDFACTOR
{
char chrMulOp = ' ';
int intStartIndex = 0;
if (!mulFactor(strInfix, strPolish, intPtrIndex, intEnd))
{
errorHandlerSyntax(*intPtrIndex,
"mulFactor not found",
strInfix);
return 0;
}
if (*intPtrIndex > intEnd) return -1;
intStartIndex = *intPtrIndex;
while (1)
{
SKIP_WHITE_SPACE(strInfix, (*intPtrIndex), intEnd)
if (*intPtrIndex > intEnd) break;
if ((chrMulOp = strInfix[*intPtrIndex]) != '*'
&&
chrMulOp != '/')
return -1;
(*intPtrIndex)++;
if (*intPtrIndex > intEnd
||
!mulFactor(strInfix,
strPolish,
intPtrIndex,
intEnd))
return errorHandlerSyntax
(*intPtrIndex,
"Mul/div op not followed by mulFactor",
strInfix);
if (!stringAppendChar(strPolish,
chrMulOp,
MAX_POLISH_LENGTH,
1)) return 0;
}
return -1;
}
// ---------------------------------------------------------------
// Error handler
//
// int errorHandler(char *strMessage)
//
ERRORHANDLER
{
printf("\n%s\n", strMessage); return 0;
}
// ---------------------------------------------------------------
// Syntax error handler
//
// int errorHandlerSyntax(int intIndex,
// char *strMessage,
// char *strInfix)
//
ERRORHANDLERSYNTAX
{
int intIndex1 = 0;
printf("\nError at character %d: %s\n",
intIndex,
strMessage);
printf("%s\n", strInfix);
for (intIndex1 = 0; intIndex1 < intIndex; intIndex1++)
printf(" ");
printf("$");
return 0;
}
// ---------------------------------------------------------------
// Parse expression
//
// int expression(char *strInfix,
// char *strPolish,
// int *intPtrIndex,
// int intEnd)
//
EXPRESSION
{ /* expression = addFactor [ +|- addFactor ] */
char chrAddOp = ' ';
int intStartIndex = 0;
if (!addFactor(strInfix, strPolish, intPtrIndex, intEnd))
{
errorHandlerSyntax(*intPtrIndex,
"addFactor not found",
strInfix);
return 0;
}
intStartIndex = *intPtrIndex;
while (1)
{
SKIP_WHITE_SPACE(strInfix, (*intPtrIndex), intEnd)
if (*intPtrIndex > intEnd) break;
if ((chrAddOp = strInfix[*intPtrIndex]) != '+'
&&
chrAddOp != '-')
return
errorHandlerSyntax
(*intPtrIndex,
"Unrecognizable char found instead of add op",
strInfix);
(*intPtrIndex)++;
if (*intPtrIndex > intEnd
||
!addFactor(strInfix,
strPolish,
intPtrIndex,
intEnd))
return errorHandlerSyntax
(*intPtrIndex,
"Add/sub op not followed by addFactor",
strInfix);
stringAppendChar(strPolish,
chrAddOp,
MAX_POLISH_LENGTH,
1);
}
return -1;
}
// ---------------------------------------------------------------
// Convert infix to Polish
//
// char *infix2Polish(char *strInfix)
//
INFIX2POLISH
{
int intIndex = 0;
char *strPolish = malloc(MAX_POLISH_LENGTH);
if (strPolish == 0)
errorHandler("Can't get storage");
strPolish[0] = '\0';
if (!expression(strInfix,
strPolish,
&intIndex,
stringLength(strInfix) - 1))
{
errorHandler("Can't parse expression");
return "";
}
return strPolish;
}
// ---------------------------------------------------------------
// Parse multiplication factor
//
// int mulFactor(char *strInfix,
// char *strPolish,
// int *intPtrIndex,
// int intEnd)
//
// mulFactor = LETTER | NUMBER | '(' expression ')'
//
MULFACTOR
{ int intIndexStart = 0;
int intLevel = 0;
char chrNext = ' ';
int intInner = 0;
int intSpaceBefore = 0;
SKIP_WHITE_SPACE(strInfix, (*intPtrIndex), intEnd)
if (*intPtrIndex > intEnd)
return errorHandlerSyntax(*intPtrIndex,
"mulFactor unavailable",
strInfix);
chrNext = strInfix[*intPtrIndex];
if (chrNext >= 'a' && chrNext <= 'z')
{
(*intPtrIndex)++;
return stringAppendChar(strPolish,
chrNext,
MAX_POLISH_LENGTH,
1);
}
intIndexStart = *intPtrIndex;
intSpaceBefore = -1;
while(*intPtrIndex <= intEnd
&&
(chrNext = strInfix[*intPtrIndex]) >= '0'
&&
chrNext <= '9')
{
if (!stringAppendChar(strPolish,
chrNext,
MAX_POLISH_LENGTH,
intSpaceBefore))
return 0;
intSpaceBefore = 0;
(*intPtrIndex)++;
}
if (*intPtrIndex > intIndexStart)
return -1;
if (chrNext == '(')
{
intLevel = 1;
(*intPtrIndex)++;
intInner = *intPtrIndex;
while (intLevel > 0 && *intPtrIndex <= intEnd)
{
if ((chrNext = strInfix[(*intPtrIndex)++]) == '(')
{
intLevel++;
}
else
{
if (chrNext == ')')
{
intLevel--;
}
}
}
if (intLevel != 0)
return errorHandlerSyntax
(*intPtrIndex,
"Unbalanced left parenthesis",
strInfix);
if (!expression(strInfix,
strPolish,
&intInner,
*intPtrIndex - 2))
return errorHandlerSyntax
(intInner,
"Expression doesn't appear in parentheses",
strInfix);
return -1;
}
return 0;
}
// ---------------------------------------------------------------
// Append character to string
//
// int stringAppendChar(char *strInstring,
// char chrNew,
// int intMaxLength,
// int intSpaceBefore)
//
STRINGAPPENDCHAR
{
int intLength = stringLength(strInstring);
int intSpaceBeforeInEffect =
intSpaceBefore
&&
intLength > 0
&&
strInstring[intLength - 1] != ' ';
if (intLength
>=
intMaxLength - (intSpaceBeforeInEffect ? 2 : 1))
{
errorHandler
("Cannot append character(s): string too long");
return 0;
}
if (intSpaceBeforeInEffect)
{
strInstring[intLength++] = ' ';
}
strInstring[intLength] = chrNew;
strInstring[intLength + 1] = '\0';
return -1;
}
// ---------------------------------------------------------------
// Return string length
//
// int stringLength(char *strInstring)
//
STRINGLENGTH
{
int intIndex1;
for (intIndex1 = 0;
strInstring[intIndex1] != '\0';
intIndex1++) { }
return intIndex1;
}
// ---------------------------------------------------------------
// Test case
//
// void testCase(char *strInfix, char *strExpected)
//
TESTCASE
{
printf("\n\nConverting \"%s\": expect \"%s\"",
strInfix,
strExpected);
printf("\n\"%s\"\n",
infix2Polish(strInfix));
}
// ---------------------------------------------------------------
// Tester
//
// void tester()
//
TESTER
{
testCase("(10+613)*a", "10 613 + a *");
testCase(")", "Error");
testCase("1)", "Error");
testCase("(((1))))", "Error");
testCase("10 113 + a *", "Error");
testCase("(10 + 113) * a", "10 113 + a *");
testCase(" ( 10 + 113 ) * a ", "10 113 + a *");
testCase("(", "Error");
testCase("((((2", "Error");
testCase("////2", "Error");
testCase("", "Error");
testCase("()", "Error");
testCase("(((5))", "Error");
testCase("(((5)))", "5");
testCase("((5))", "5");
testCase("5", "5");
testCase("((10+(113-(2+((((((2/(4+3)))))))+2+2))))*a", "10 113 2 2 4
3 + / + 2 + 2 + - + a *");
testCase("1+1", "1 1 +");
testCase("a", "a");
testCase(" a + b ", "a b +");
}
Converting "(10+613)*a": expect "10 613 + a *"
"10 613 + a *"
Converting ")": expect "Error"
Error at character 0: mulFactor not found
)
$
Error at character 0: addFactor not found
)
$
Can't parse expression
""
Converting "1)": expect "Error"
Error at character 1: Unrecognizable char found instead of add op
1)
$
Can't parse expression
""
Converting "(((1))))": expect "Error"
Error at character 7: Unrecognizable char found instead of add op
(((1))))
$
Can't parse expression
""
Converting "10 113 + a *": expect "Error"
Error at character 3: Unrecognizable char found instead of add op
10 113 + a *
$
Can't parse expression
""
Converting "(10 + 113) * a": expect "10 113 + a *"
"10 113 + a *"
Converting " ( 10 + 113 ) * a ": expect "10 113 + a *"
"10 113 + a *"
Converting "(": expect "Error"
Error at character 1: Unbalanced left parenthesis
(
$
Error at character 1: mulFactor not found
(
$
Error at character 1: addFactor not found
(
$
Can't parse expression
""
Converting "((((2": expect "Error"
Error at character 5: Unbalanced left parenthesis
((((2
$
Error at character 5: mulFactor not found
((((2
$
Error at character 5: addFactor not found
((((2
$
Can't parse expression
""
Converting "////2": expect "Error"
Error at character 0: mulFactor not found
////2
$
Error at character 0: addFactor not found
////2
$
Can't parse expression
""
Converting "": expect "Error"
Error at character 0: mulFactor unavailable
$
Error at character 0: mulFactor not found
$
Error at character 0: addFactor not found
$
Can't parse expression
""
Converting "()": expect "Error"
Error at character 1: mulFactor unavailable
()
$
Error at character 1: mulFactor not found
()
$
Error at character 1: addFactor not found
()
$
Error at character 1: Expression doesn't appear in parentheses
()
$
Error at character 2: mulFactor not found
()
$
Error at character 2: addFactor not found
()
$
Can't parse expression
""
Converting "(((5))": expect "Error"
Error at character 6: Unbalanced left parenthesis
(((5))
$
Error at character 6: mulFactor not found
(((5))
$
Error at character 6: addFactor not found
(((5))
$
Can't parse expression
""
Converting "(((5)))": expect "5"
"5"
Converting "((5))": expect "5"
"5"
Converting "5": expect "5"
"5"
Converting "((10+(113-(2+((((((2/(4+3)))))))+2+2))))*a": expect "10
113 2 2 4 3 + / + 2 + 2 + - + a *"
"10 113 2 2 4 3 + / + 2 + 2 + - + a *"
Converting "1+1": expect "1 1 +"
"1 1 +"
Converting "a": expect "a"
"a"
Converting " a + b ": expect "a b +"
"a b +"