home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!mcsun!sun4nl!and!jos
- From: jos@and.nl (Jos Horsmeier)
- Newsgroups: comp.lang.c
- Subject: Re: How can you evaluate an arbitrary function?
- Message-ID: <4302@dozo.and.nl>
- Date: 7 Jan 93 09:16:09 GMT
- References: <1993Jan6.202453.8630@news.tufts.edu>
- Organization: AND Software BV Rotterdam
- Lines: 96
-
- In article <1993Jan6.202453.8630@news.tufts.edu> slahiri@jade.tufts.edu (Sandip Lahiri) writes:
- |Suppose you have to write a program which would accept any arbitrary
- |function f(x) and calculate its values for x = ... . The program has
- |to be written in C. How would you go about it ? [ ... ]
-
- Two approaches come to mind:
-
- - Use yacc and lex (or equivalent tools) to generate the parser and
- lexical analyzer for you;
-
- - Write your own parser and lexical analyzer.
-
- The grammar for this particular language (well formed expressions) is
- not too difficult to construct. Many textbooks give skeletons of such
- a grammar (e.g. the Dragon Book) If you want to build your own parser,
- may I suggest to construct a right recursive grammar first (or more
- specifically: an LL(1) grammar) because the derivation of the actual
- C code from it is very easy to do. A short example may clarify things
- a bit. The following three rules:
-
- E = T { [+-] E }
- T = F { [*/] T }
- F = x | c | f ( E ) | ( E ) | - F
-
- make up a fairly complete syntax for arithmetic expressions. (f = any
- function name, x = the function parameter, c = any constant) These rules
- can directly be translated to C as follows:
-
- double E() {
-
- double Result = T();
-
- for(;;)
- switch (Token()) {
- case '+': Result+= T(); break;
- case '-': Result-= T(); break;
- default : PushBackToken();
- return Result;
- }
- return Result;
- }
-
-
- double T() {
-
- double Result = F();
-
- for(;;)
- switch (Token()) {
- case '*': Result+= F(); break;
- case '/': Result-= F(); break;
- default : PushBackToken();
- return Result;
- }
- return Result;
- }
-
- double F() {
-
- double Result;
-
- switch (Token()) {
- case 'x': return GetParValue();
- case 'c': return GetConstValue();
- case '-': return -F();
- case '(': Result= E();
- if (token() != ')') {
- perror("')' expected");
- abort();
- }
- case 'f': if (token() != ')') {
- perror("'(' expected");
- abort();
- }
- Result= E();
- if (token() != ')') {
- perror("')' expected");
- abort();
- }
- return ApplyFunc(Result);
- default : perror("Syntax error");
- abort();
- }
- }
-
- Well, I hope you get the picture ... Recursive descent parsing is not
- the difficult part. Building a lexical analyzer can be a tedious job:
- it not only has to recognize floating point constants and function
- names (and parentheses, operators etc.) but it also has to transform
- the string representation of those constants into an internal repre-
- sentation (double type) It's much more convenient to use lex (or a
- similar tool) for that.
-
- I hope this helps a bit. Kind regards,
-
- Jos aka jos@and.nl
-