ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
The compiler doesn't know what "Node" is at line 13, because it isn't defined until later, at line 27. Since you have two structures that use each others' types, you need a partial declaration. Plus you have some other mistakes, like duplicate definitions of the typedef name NodeLitIntValues at lines 20 and 25.
May I suggest defining your types this way:
Code:
struct node;
typedef struct node_op_values {
int type;
int numOps;
struct node** ops;
} NodeOpValues;
typedef struct {
int value;
} NodeLitIntValues;
typedef struct {
char id;
} NodeVarValues;
typedef struct node {
int type;
union {
NodeOpValues opValues;
NodeLitIntValues litIntValues;
NodeVarValues varValues;
};
} Node;
(Of course you don't need a structure if you have only one field inside it, but it's not incorrect, only superfluous.)
Even given the corrected types, you have some other problems, like for example parseNode() and freeNode() have no return value, yet you're using calls to them in your "statements" rule as if they have a return value. But you can work on those once the type definitions are right.
Click here to see the post LQ members have rated as the most helpful post in this thread.
$ gcc *.c -o lang
lang.y: In function ‘yyparse’:
lang.y:52: warning: passing argument 1 of ‘parseNode’ makes pointer from integer without a cast
lang.y:38: note: expected ‘struct Node *’ but argument is of type ‘YYSTYPE’
lang.y:52: warning: passing argument 1 of ‘freeNode’ makes pointer from integer without a cast
lang.y:39: note: expected ‘struct Node *’ but argument is of type ‘YYSTYPE’
lang.y:60: warning: assignment makes integer from pointer without a cast
lang.y:61: warning: assignment makes integer from pointer without a cast
lang.y:62: warning: assignment makes integer from pointer without a cast
lang.y:63: warning: assignment makes integer from pointer without a cast
lang.y:64: warning: assignment makes integer from pointer without a cast
lang.y:65: warning: assignment makes integer from pointer without a cast
lang.y:66: warning: assignment makes integer from pointer without a cast
lang.y:67: warning: assignment makes integer from pointer without a cast
lang.y: In function ‘mkVarNode’:
lang.y:88: error: ‘value’ undeclared (first use in this function)
lang.y:88: error: (Each undeclared identifier is reported only once
lang.y:88: error: for each function it appears in.)
lang.y: In function ‘mkOpNode’:
lang.y:100: error: redeclaration of ‘i’ with no linkage
lang.y:99: note: previous declaration of ‘i’ was here
lang.y:100: error: ‘for’ loop initial declarations are only allowed in C99 mode
lang.y:100: note: use option -std=c99 or -std=gnu99 to compile your code
lang.y: In function ‘parseNode’:
lang.y:112: error: ‘vars’ undeclared (first use in this function)
lang.y: In function ‘freeNode’:
lang.y:134: error: ‘opNodeType’ undeclared (first use in this function)
lang.y:135: error: ‘i’ undeclared (first use in this function)
lang.y:139: error: expected declaration or statement at end of input
for constructing a calculator , use following lex code:
%{
#include <stdlib.h>
#include <stdio.h>
#include "y.tab.h"
void yyerror(char*);
int varindex(char *var);
%}
Maybe it would help to know why you've been trying to use lex and yacc. I know you're trying to write a calculator program, but is the purpose just to learn about parsing, or to learn about lex and yacc, or do you have some specific application you need to work for some reason?
Unlike Sergei I don't necessarily think that using lex/yacc is a bad idea, even if it may be overkill for what you're trying to do; I often use languages or tools that are not necessary for what I'm trying to do, just for the purpose of trying to learn (or improve my knowledge of) something new. But that may not apply to what you're trying to do, so perhaps knowing more about what you're trying to accomplish by using lex and yacc can help others point you in the best direction.
Will those approaches be as fast, or almost as fast, as Lex/YACC in C, and do they work in a similar way?
Fast in what sense ? The time you spend or the speed of the final product ?
What is "similar" in "do they work in a similar way?" ?
Anyway, you will spend less time because it will be easier to debug your mistakes, and the final code will be practically as fast as generated by lex/yacc if you know what you are doing.
If you look from a wider and more practical point of view, the compiler speed is not that important nowadays - real life projects consist of many files which can be compiled in parallel, and HW is cheap.
And the compiler spends most of its time in optimizations - they are not related to frontend (lex + yacc comprise frontend).
This is mostly to learn how parsing, interpreters, and compilers work.
@Sergei Steshenko
Fast is in the sense that the compiler/interpreter using your alternative will not be significantly slower than one using Lex/YACC.
I mean "similar" in the sense that it uses a lexer to create tokens, and a LALR parser to process the tokens.
I was considering that using dynamic arrays might be a better idea than the complicated blend of structs and unions used now. The first element of the array would contain the type of node, and the rest of the elements would be interpreted accordingly.
Also, how could I handle a language that has multiple types, such as integers, floats, strings, and maybe even pointers?
This is mostly to learn how parsing, interpreters, and compilers work.
My personal opinion is that lex/yacc are not the wrong tools to use in this case, although my advice would strongly be to first read a compilers text. Maybe you already have, but from some of your earlier comments it seemed as if not.
...
I mean "similar" in the sense that it uses a lexer to create tokens, and a LALR parser to process the tokens.
I was considering that using dynamic arrays might be a better idea than the complicated blend of structs and unions used now. The first element of the array would contain the type of node, and the rest of the elements would be interpreted accordingly.
Also, how could I handle a language that has multiple types, such as integers, floats, strings, and maybe even pointers?
As I said, one doesn't need tokens. Consider input stream as the one of legal (and nested) language constructs. Consider parsing as trying in each parser state to find a language construct which fits the list of allowed ones in that state.
Yes, a dynamic language like Perl is more convenient, though don't expect too much speed from Perl. OTOH, you do not yet need speed. By the way, Perl parses pretty fast due to good RE engine, but multi-line parsing is somewhat of a nuisance in Perl.
Multiple types fit the various language constructs concept.
As I said, one doesn't need tokens. Consider input stream as the one of legal (and nested) language constructs. Consider parsing as trying in each parser state to find a language construct which fits the list of allowed ones in that state.
I still don't understand how it will work without a lexer, but...
Quote:
Originally Posted by Sergei Steshenko
Yes, a dynamic language like Perl is more convenient, though don't expect too much speed from Perl. OTOH, you do not yet need speed. By the way, Perl parses pretty fast due to good RE engine, but multi-line parsing is somewhat of a nuisance in Perl.
The multi-line thing isn't of much concern to me, because my toy language will probably be line-oriented, something like this:
Code:
while a != b
if a > b
a -= b
else
b -= a
fi
loop
Quote:
Originally Posted by Sergei Steshenko
Multiple types fit the various language constructs concept.
I still don't understand how it will work without a lexer, but...
...
Again, consider that a language construct can be as simple as a single character and as complex as the whole program. The whole program is a nested language construct consisting of, say, declarations and operators.
Declarations are nested language constructs consisting of, say, type keyword and variables list, e.g.
Code:
int a, b, c;
Variables list is a nested construct consisting of single variable optionally followed by list separator and variables list; this left recursion can be easily implemented through iteration.
List separator is a (possibly) nested languages construct consisting of comma (comma is a good example of single character language construct) optionally surrounded by whitespaces and/or comments.
Nowhere in my explanations I needed the notion of token. Nowhere in my explanation I assumed a context-free grammar.
Last edited by Sergei Steshenko; 03-20-2010 at 05:28 PM.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.