Why should we give a solution at all? (My emphasis, admittedly.)
And I'd rather have the pointer than a global variable running around somewhere -- and who said the string came from the user typing it in anyway?
Printable View
i got a really big bug
the program says that "(,)(,)(,)" valid
why??
Code:#include <stdio.h>
#include <ctype.h>
int is_valid(const char *input);
const char *match_pair(const char *input);
int main()
{
char input[] = "(,)(,)(,)";
if (is_valid(input))
{
printf("%s is valid.\n", input);
}
else
{
printf("%s is invalid.\n", input);
}
return 0;
}
/* Match one or more consecutive digits and return a pointer to the first char
* that is not a digit.
*/
const char *match_number(const char *input)
{
while((*input<='9')&&(*input>='0')){
input++; //increasing the address by1
}
return input;
}
/* Match "(<number>,<number>)" pattern.
* Return a pointer to the first char after the matched pattern, or
* NULL if there is no match.
*/
const char *match_pair(const char *input)
{
if (*input != '(')
{
return NULL;
}
input = match_number(input + 1); //it wiil get char '2'
if (*input == ',') { //'2' differs ','
input = match_number(input + 1);
if (*input==')'){
return input+1;
}
else
return NULL;
}
else
return NULL;
}
/* Match "(<number>,<number>) (<number>,<number>) (<number>,<number>)" pattern.
* Return 1 if there is a match and 0 otherwise.
*/
/* Match one or more "(<number>,<number>)" pairs separated by a space.
* Return 1 if there is a match and 0 otherwise.
*/
int is_valid(const char *input)
{
/* Match "(<number>,<number>)" */
input = match_pair(input);
if (input == NULL)
{
return 0;
}
/* Match zero or more " (<number>,<number>)" */
while (*input != '\0')
{
input = match_pair(input);
if (input == NULL)
{
return 0;
}
}
return 1;
}
i tried to insert before i check go on the match number
its not working
Code:if ((*input>'9')&&(*input<'0')) {
return 0;
}
solved it :)
hmm... yes, that is a mistake on my part. The code I gave matches zero or more digits, but you want to match one or more digits.Quote:
Originally Posted by transgalactic2
Nonetheless, it is good to see that you are attempting to fix it by returning 0. Unfortunately, you cannot do it that way. Rather, do something like what match_pair() does when it detects invalid input:
Of course, this means that match_pair() now has to check the return value of match_number(), e.g., you need to change:Code:const char *match_number(const char *input)
{
if (!isdigit(*input))
{
return NULL;
}
++input;
while (isdigit(*input))
{
++input;
}
return input;
}
to:Code:input = match_number(input + 1);
Code:if ((input = match_number(input + 1)) == NULL)
{
return NULL;
}
I solved this problem.
unfortunetly i was told that i cant use pointers.
in order to overcome this obstickle i need to combine the three external functions
into one and then i will change each astrix with an array definition
i managed to combine them in to two function.
when i tried to combine the 2 left ones.
instead of return input+1; i wrote input++;
and instead of return NULL; i wrote input=NULL
i did copy paste
its not working
??
this code is the working two function code
Code:#include <stdio.h>
int is_valid(const char *input);
const char *match_pair(const char *input);
int main()
{
char input[] = "(1,2)(3,4)(5,9)";
if (is_valid(input))
{
printf("%s is valid.\n", input);
}
else
{
printf("%s is invalid.\n", input);
}
return 0;
}
/* Match one or more consecutive digits and return a pointer to the first char
* that is not a digit.
*/
/* Match "(<number>,<number>)" pattern.
* Return a pointer to the first char after the matched pattern, or
* NULL if there is no match.
*/
const char *match_pair(const char *input)
{
if (*input != '(')
{
return NULL;
}
if ((*(input+1)<'0')||(*(input+1)>'9')){
return NULL;
}
input++;
while((*input<='9')&&(*input>='0')){
input++; //increasing the address by1
} //it wiil get char '2'
if (*input == ',') { //'2' differs ','
if ((*(input+1)<'0')||(*(input+1)>'9')){
return NULL;
}
input++;
while((*input<='9')&&(*input>='0')){
input++; //increasing the address by1
}
if (*input==')'){
return input+1;
}
else
return NULL;
}
else
return NULL;
}
/* Match "(<number>,<number>) (<number>,<number>) (<number>,<number>)" pattern.
* Return 1 if there is a match and 0 otherwise.
*/
/* Match one or more "(<number>,<number>)" pairs separated by a space.
* Return 1 if there is a match and 0 otherwise.
*/
int is_valid(const char *input)
{
/* Match "(<number>,<number>)" */
input = match_pair(input);
if (input == NULL)
{
return 0;
}
/* Match zero or more " (<number>,<number>)" */
while (*input != '\0')
{
input = match_pair(input);
if (input == NULL)
{
return 0;
}
}
return 1;
}
i cant combine these two into one is_valid function.
You mean that you have not learnt about pointers yet?Quote:
Originally Posted by transgalactic2
No, if you cannot use pointers then the next best option is to adapt what audinue suggested, i.e., use a getChar() function with a char (I would prefer it local, but global is more common in the literature) to hold the current character under consideration. Basically, wherever you need to increment the pointer you would replace it with a call to getChar(), with some syntax changes, of course.Quote:
Originally Posted by transgalactic2
we cant use recurtion either so
audinue suggestion is the same thing as pointer.
It almost done i need to combine them both.
when i will have one big is_valid function
which returns 1 or 0
i will simply replace every pointer definition with array
but i need this big is_valid function
i tried to addapt match_pair and do copy paste
but its not working
??
Code:#include <stdio.h>
int is_valid(const char *input);
const char *match_pair(const char *input);
int main()
{
char input[] = "(1,2)(3,4)(555,9)";
if (is_valid(input))
{
printf("%s is valid.\n", input);
}
else
{
printf("%s is invalid.\n", input);
}
return 0;
}
/* Match one or more consecutive digits and return a pointer to the first char
* that is not a digit.
*/
/* Match "(<number>,<number>)" pattern.
* Return a pointer to the first char after the matched pattern, or
* NULL if there is no match.
*/
const char *match_pair(const char *input)
{
if (*input != '(')
{
return NULL;
}
if ((*(input+1)<'0')||(*(input+1)>'9')){
return NULL;
}
input++;
while((*input<='9')&&(*input>='0')){
input++; //increasing the address by1
} //it wiil get char '2'
if (*input == ',') { //'2' differs ','
if ((*(input+1)<'0')||(*(input+1)>'9')){
return NULL;
}
input++;
while((*input<='9')&&(*input>='0')){
input++; //increasing the address by1
}
if (*input==')'){
return input+1;
}
else
return NULL;
}
else
return NULL;
}
/* Match "(<number>,<number>) (<number>,<number>) (<number>,<number>)" pattern.
* Return 1 if there is a match and 0 otherwise.
*/
/* Match one or more "(<number>,<number>)" pairs separated by a space.
* Return 1 if there is a match and 0 otherwise.
*/
int is_valid(const char *input)
{
/* Match "(<number>,<number>)" */
input = match_pair(input);
if (input == NULL)
{
return 0;
}
/* Match zero or more " (<number>,<number>)" */
while (*input != '\0')
{
input = match_pair(input);
if (input == NULL)
{
return 0;
}
}
return 1;
}
Actual recursive descent parsing does not happen here, which is why I said audinue introduced "something new (and not really new either in the basic idea)". The basic idea is to use a function to parse some portion of the input that matches, or should match, a corresponding part of the format pattern. Hence the match_number(), match_whitespace() and match_pair() functions, or in audinue's example the expectNumber(), skipWhite() and expression() functions.Quote:
Originally Posted by transgalactic2
What I am suggesting that you adapt is the use of the getChar() function. It effectively serves the same purpose as incrementing the input pointer, except that the input pointer is more flexible since it works on a string rather than directly from stdin.
That is a bad idea. Stop trying to combine your normal sized functions into one big function.Quote:
Originally Posted by transgalactic2
Don't forget, recursive descent parsing has a strict rule that should be obeyed.
No exceptions, includingthings.Code:(,)
That simplicity the problem, and nearly bug-less(with a very good design of course), so that's why I suggest you, transgalactic2, to learn that laserlight called "something new" for your next better ideas and purposes.
Could you explain that? I have never heard of such a rule. The rule that should be obeyed is that the parser's structure should follow the production rules of the grammar, though sometimes the rules may need to be tweaked to avoid left recursion.Quote:
Originally Posted by audinue
I agree, but audinue, I suspect that you have a very narrow idea of what is recursive descent parsing: my code is no less (or no more, for that matter) of a recursive descent parser than yours. The main difference is how the input is retrieved (and it turns out that a variant of your way has to be used anyway, since transgalactic2 did not mention that pointers were not allowed).Quote:
Originally Posted by audinue
I mean, statement like:Quote:
Could you explain that? I have never heard of such a rule. The rule that should be obeyed is that the parser's structure should follow the production rules of the grammar, though sometimes the rules may need to be tweaked to avoid left recursion.
Will throw an error if we don't input a left/open parenthesis.Code:expect('(');
So, something readable statements like:
Will obey the rule: (<number>, <number>)Code:expect('('); expectNumber(); expect(','); expectNumber(); expect(')');
And will accept: (1, 2) | (22, 33) | etc.
These will never happen: (,) | [,] | , | x | 999 | another else.
Instead of nesting loop, you ...err... maybe only me ;) LOL ... should think twice to make an algorithm that works like that.
My eyes got jumpy whenever I'm looking at pointers and dereferences xD especially for unformatted tabs.Quote:
I agree, but audinue, I suspect that you have a very narrow idea of what is recursive descent parsing: my code is no less (or no more, for that matter) of a recursive descent parser than yours. The main difference is how the input is retrieved (and it turns out that a variant of your way has to be used anyway, since transgalactic2 did not mention that pointers were not allowed).
Sorry, I didn't mention it. Currently, I just know that RDP parser is full of thing like match, expect, next, getchar, separated and specified algorithm routines to parse thing.
hmm... but that should be true of any parser: invalid syntax should result in an error.Quote:
Originally Posted by audinue
However, that does not really describe what is a recursive descent parser. As I mentioned, one of the primary characteristics of a recursive descent parser is that the parser's structure should follow the production rules of the grammar. The "recursive" part is from the fact that the rules are often (mutually) recursive in nature, hence the code would be recursive as well. The "descent" part is probably just a fancy way of describing how the function calls "descend" into a call stack.Quote:
Originally Posted by audinue
how to change this code so it will check only one
num,num
no cols the pattern must be num,num
a legal input "2,25"
illegal input "2,25 " or " 5, 24"
no spaces
the problem is that match_number returns one place after the number
which is not supposed to be
because the string ends with a number
i wrote this code and inserted "2,1" it said that its invalid
why
??
Code:
#include <stdio.h>
int is_valid(const char *input);
const char *match_number(const char *input);
int main()
{
int i;
int ch;
int input[40];
printf("enter string\n");
for (i = 0; i < 39 && (ch = getchar()) != '\n' && ch != EOF; ++i)
{
input[i] = ch;
}
input[i] = '\0';
if (is_valid(input))
{
printf("%s is valid.\n", input);
}
else
{
printf("%s is invalid.\n", input);
}
return 0;
}
/* Match one or more consecutive digits and return a pointer to the first char
* that is not a digit.
*/
const char *match_number(const char *input)
{
while((*input<='9')&&(*input>='0')){
input++; //increasing the address by1
}
return input;
}
int is_valid(const char *input)
{
if (((*input)<'0')||((*input)>'9')){
return 0;
}
input=match_number(input);
if (*input==','){
input=match_number(input+1);
if (*input=='\0'){
return 1;
}
}
else
{
return 0;
}
}