GMPC 1.0.0 Manual

SourceForge.net Logo

Table of Contents


Next: , Up: (dir)

GMPC

This manual describes how to use the GMP compiler, version 1.0.0 (23 December 2006)

Copyright (C) 2006 Free Software Foundation, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being "A GNU Manual", and with the Back-Cover Texts being "You have freedom to copy and modify this GNU Manual, like GNU software".


Next: , Previous: Top, Up: Top

1 Introduction

The gmpc tool simplifies the use of GMP, the GNU multiple precision library. It scans a C source file for specially marked GMPS arithmetic expressions and replaces them with plain C.

The abbreviation gmpc stands for GMP compiler, or alternatively GMPS-to-C compiler. GMPS arithmetic expressions are straightforward infix expressions which transparently support the special types mpq_t, mpz_t and mpf_t as defined by GMP. GMPS means, rather unimaginatively, `GMP script'.

No dependencies are added to the resulting C source, so there is no need to include additional header files or link with special libraries other than GMP.


Next: , Previous: Introduction, Up: Top

2 Downloading and installing

The gmpc distribution can be downloaded here:

http://gmpc.sourceforge.net.

On UNIX-like systems, a basic build can be done with

     ./configure
     make

The configure script has a lot of useful options. Try ./configure --help to see them. Installation can be done with

     make install

Regression tests are accessible through the check target.

     make check

The tests directory contains the *.gmpc files under test.


Next: , Previous: Downloading and installing, Up: Top

3 Invoking gmpc

To translate a .gmpc file to C source, at least the input and output files must be given. The most concise invocation would look like this:

       gmpc -o foo.c foo.gmpc

This will translate foo.gmpc into foo.c.

It is highly recommended to enable all warnings with the -Wall switch:

       gmpc -Wall -o foo.gmpc foo.c

Other switches can be used to change the default behaviour of gmpc. They are listed in the following sections.


Next: , Previous: Invoking gmpc, Up: Invoking gmpc

3.1 Output base

The generated C code usually contains numerical constants. The output base in which all mpq_t, mpz_t and mpf_t constants are represented can be set with the -fbase switch. The following example will cause all constants to be hexadecimal.

       gmpc -fbase=16 -o foo.c foo.gmpc

The default base is 10. If you are not interested in generating human-readable code, a power of 2 (e.g. 16) may be more space and time efficient.


Next: , Previous: Output base, Up: Invoking gmpc

3.2 Float digits

The generated C code may contain mpf_t constants. The -ffloat-digits option can be used to set the number of digits. The following example will set the number of mpf_t digits to 120.

       gmpc -ffloat-digits=120 -o foo.c foo.gmpc

Note that the number of digits in double (the native C type) constants is controlled by the -fdouble-format switch.


Next: , Previous: Float digits, Up: Invoking gmpc

3.3 Double format

The generated C code may contain double constants. The -fdouble-format option can be used to set the formatting of such constants using a printf-like format specifier. The following example will set the number of double digits to 20, with trailing zeros removed.

       gmpc -fdouble-format=%.20g -o foo.c foo.gmpc

The default value is %24.24e.


Next: , Previous: Double format, Up: Invoking gmpc

3.4 Precision

gmpc uses GMP to evaluate constant expressions. The default precision for mpf_t calculations is set with -fprecision. This is the value that is passed to mpf_set_default_prec internally. Its default value is <float digits> * log <base> / log <2> + 1.


Next: , Previous: Precision, Up: Invoking gmpc

3.5 Prefix

The generated C code may contain declarations and definitions of temporary variables. In order to avoid name space pollution, a suitable prefix for all symbols can be set with the -fprefix option.

The following example will prefix all symbols with yy.

       gmpc -fprefix=yy -o foo.c foo.gmpc

The default value is gmps.


Next: , Previous: Prefix, Up: Invoking gmpc

3.6 Catching undefined variables

Using a variable before it is defined (using either import or var GMPS statements) will automatically create it. To guard against typos or the creation of variables of unexpected types, gmpc has the option -Wundefined-variables to show a warning when a variable is created automatically.

This option is implied by the -Wall switch.


Next: , Previous: Catching undefined variables, Up: Invoking gmpc

3.7 Catching missing sections

In order to be useful, a .gmpc file should contain GMPS statements for at least the following 4 sections:

  1. declarations
  2. init
  3. body
  4. cleanup

The option -Wmissing-sections will cause gmpc to emit a warning for each missing section.

This option is implied by the -Wall switch.


Next: , Previous: Catching missing sections, Up: Invoking gmpc

3.8 Catching unused expressions

Unused expressions are wasteful, even if they have useful side-effects. In the following example, the assignment to dr is carried out, but the result of +1 is not used.

       %% mpf_t 1 + (dr = mpf_sqrt(dx*dx + dy*dy));

If the option -Wunused-expressions is used, the first + will trigger a warning.

This option is implied by the -Wall switch.


Next: , Previous: Catching unused expressions, Up: Invoking gmpc

3.9 Enabling all warnings

The option -Wall enables all warnings, i.e. -Wundefined-variables, -Wunused-expressions and -Wmissing-sections.


Next: , Previous: Enabling all warnings, Up: Invoking gmpc

3.10 Suppressing linemarkers

The option -fno-linemarkers inhibits the inclusion of #line xxx lines in the generated C code.


Next: , Previous: Suppressing linemarkers, Up: Invoking gmpc

3.11 Listing supported GMP functions

The option -fdump-prototypes causes gmpc to list all supported GMP functions, and exit.


Next: , Previous: Listing supported GMP functions, Up: Invoking gmpc

3.12 Version number

The option -version causes gmpc to print its version number on stdout, and exit.


Previous: Version number, Up: Invoking gmpc

3.13 Help

The option -help causes gmpc to print a short help message on stdout, and exit.


Next: , Previous: Invoking gmpc, Up: Top

4 GMPS statements

GMPS statements are the statements that are actually seen by gmpc. GMPS statements are embedded in C code. To distinguish GMPS from C, a GMPS line starts with %%. Lines that do not start with this special token are considered C source, and copied to the output file without any interpretation.

GMPS lines are usually replaced with generated C source, although sometimes they are just there to tell gmpc something.

Arithmetic expressions can freely mix mpq_t, mpz_t and mpf_t variables and constants with the native C types int, long int and unsigned long int.

There are no control statements like branches and loops in GMPS. These things should be handled in C.

The next sections deal with GMPS in more detail.


Next: , Previous: GMPS, Up: GMPS

4.1 Comments

Since gmpc ignores C code lines, using C-style comments to comment out sections of code will not prevent gmpc from interpreting GMPS statements.

In the next example, gmpc will still create code for the init, body and cleanup sections, which end up as C-comments.

     int main(void)
     {
     /*
         %% init;
         foo_func();
         %% mpq_t y = (2/3)*x*x + 3*x - 1/12;
         %% cleanup;
     */
         return 0;
     }

Changing the comments to #if 0 ... #endif would have the same effect. GMPS does support C-style comments, however. The next example does not create init, body and cleanup sections.

     int main(void)
     {
     /*
         %% /* init;
         foo_func();
         %% mpq_t y = (2/3)*x*x + 3*x - 1/12;
         %% cleanup; */
     */
         return 0;
     }

Next: , Previous: Comments, Up: GMPS

4.2 Declarations section

Expressions that are translated by gmpc typically need temporary variables and constants. gmpc adds declarations for all temporaries and constants to the declarations section. In the eventual output, the declarations keyword is replaced by the full list of C declarations. It can be placed either at file scope or at function scope, although the latter only makes sense in C function that contains all 4 obligatory sections declarations, init, body and cleanup.

At file scope, a declarations section looks like this:

     %% declarations;
     int main(void)
     {
         return 0;
     }

It is also possible to make all C declarations static with %% static declarations;.


Next: , Previous: Declarations section, Up: GMPS

4.3 Init section

Expressions that are translated by gmpc typically need temporary variables and constants. The init keyword is replaced by the necessary C initialisations. It usually consists of a sequence of GMP calls like mpz_init() and mpf_set_str().

In GMPS, an init section looks like this:

     %% init;

Your code should be set up so that the generated C code is run exactly one, at startup.

Its counterpart is the cleanup section.


Next: , Previous: Init section, Up: GMPS

4.4 Cleanup section

Expressions that are translated by gmpc typically need temporary variables and constants. The cleanup keyword is replaced by the necessary C cleanup actions. It usually consists of a sequence of GMP calls like mpz_clear().

In GMPS, a cleanup section looks like this:

     %% cleanup;

If you do not want to leave any allocated memory behind, your code should be set up so that the generated C code is run exactly one, during shutdown.


Next: , Previous: Cleanup section, Up: GMPS

4.5 Importing variables

GMPS has its own name space. If you want to interface with C code generated by gmpc, you may want to import variables from your C program into GMPS's name space. This can be done with the import keyword.

In the next example, x and y are imported.

     void poly(mpq_t y, mpq_t x)
     {
         %% import mpq_t x, y;
         %% mpq_t y = (x+1)*(x-1)*x/6 + 1;
     }

Note that, since GMPS has only one name space, x and y are visible in all subsequent body sections. In fact, since the import keyword is not replaced by C code, it can be placed anywhere in the file, as long as it comes before the body section that needs the variables.

gmpc will not create any code for the declarations, init and cleanup sections if a variable is imported – it will just assume that the variable is available and ready.

Use the var keyword if you want to leave initialisation and cleanup to gmpc. For parameters, such as in the example, import should be used.


Next: , Previous: Import, Up: GMPS

4.6 Declaring variables

Using a variable before it is defined will automatically create it. To force the creation of a variable of a certain type, or to prevent warnings about undefined variables when -Wundefined-variables is used, a variable can be defined explicitly with the var keyword.

In the following example, r2 is defined explicitly.

     void poly(mpq_t y, mpq_t x)
     {
         %% import mpq_t x, y;
         %% var mpq_t r2;
         %% mpq_t {
         %%   r2 = x*x + y*y;
         %%    y = (x+1)*(x-1)*x/6 + 1;
         %% }
         gmp_printf("r2 = %Qd\n", r2);
     }

This code fragment would also work without the var statement.

Unlike imported variables, defined variables are logically owned by GMPS, but available to the C program. gmpc will create code for the declarations, init and cleanup sections.

The same is true for variables that are neither defined nor imported.


Previous: Var, Up: GMPS

4.7 Body section

The body section is where most of the work is done. It declares a default type, and contains one ore more arithmetic expressions that are translated into C code.

In the following example, the body section defines two expressions with a default type mpq_t.

     void poly(mpq_t y, mpq_t x)
     {
         %% import mpq_t x, y;
         %% body mpq_t {
         %%   r2 = x*x + y*y;
         %%    y = (x+1)*(x-1)*x/6 + 1;
         %% }
         gmp_printf("r2 = %Qd\n", r2);
     }

The body keyword is optional. If only one expression is defined, the braces can be omitted:

     void poly(mpq_t y, mpq_t x)
     {
         %% import mpq_t x, y;
         %% mpq_t y = (x+1)*(x-1)*x/6 + 1;
     }

Or, since GMPS is a free-format language:

     void poly(mpq_t y, mpq_t x)
     {
         %% import mpq_t x, y;
         %% mpq_t
         %%    y = (x+1)*(x-1)*x/6 + 1;
     }

Next: , Previous: GMPS, Up: Top

5 GMPS expressions

GMPS expressions are the arithmetic expressions that are used in body sections. The ability to translate them into plain C is the core feature of gmpc.

Arithmetic expressions are infix, and C-like, although some things are done differently to keep the expressions as clean as possible.


Next: , Previous: GMPS expressions, Up: GMPS expressions

5.1 Default type

Every expression has a default type, which is defined by the body section that contains it. This type can be mpq_t, mpz_t or mpf_t.

The main application of the default type is in constants. In the next example, all constants are mpq_t constants.

     mpq_t q = 1/2 + 1/3 + 1/4;

Default types also play an important part in the creation of undefined variables, and in implicit type conversions.


Next: , Previous: Default type, Up: GMPS expressions

5.2 Type of undefined variables

The type of an undefined variable is determined by the following rules:

  1. A reference to an undefined scalar variable will cause the creation of a variable of the default type. This variable will be initialised by GMP and therefore have a defined 0 value.
  2. An assignment to an undefined variable will trigger the creation of a variable whose type is equal to that of the right-hand side of the assignment.

Note 1: Array elements cannot be created automatically. They must be imported.

Note 2: Compound assignments like y += x; are treated as a reference followed by an assignment, so the default type will be applied if y is undefined.


Next: , Previous: Type of undefined variables, Up: GMPS expressions

5.3 Implicit type conversion

If a type conversion is needed, a C-like cast expression can be used. However, in some cases GMPS allows type mismatches and silently applies conversions.

  1. Function parameters that are `pass by value' are automatically converted.
  2. In assignments, the right-hand side is automatically converted to fit the variable on the left-hand side.

Furthermore, some operators expect operands of a certain type. Operands will be converted implicitly in the following cases:

  1. << and >> expect unsigned long int right-hand side operands. The resulting type is equal to that of the left-hand side operand.
  2. *, /, + and - expect both operands to have the same type. An appropriate mixed-type GMP function may be used, if available. For example, (mpz_t)a + (unsigned long int)b will result in an mpz_add_ui() function call. If no appropriate GMP function is found, both operands will be converted to the default type.
  3. The relational operators <, <=, >, >=, == and != convert their operands to the default type. If an appropriate mixed-type GMP function is found, it will be used instead.
  4. The boolean operators &&, || and ! expect int operands. Their result is an int.

As an exception, the bitwise operators &, |, ^ and ~ are only defined for mpz_t. No conversion is performed. gmpc will abort with an error message in case of a type mismatch.


Next: , Previous: Implicit type conversion, Up: GMPS expressions

5.4 Constants

gmpc recognises constants that are accepted by the underlying GMP functions mpX_set_str() with a base argument of 0.

For mpq_t and mpz_t, decimal constants are accepted. Furthermore, gmpc handles prefixes for hex (0x or 0X), octal (0) and binary (0b or 0B).

For mpf_t only decimal constants are accepted.

For more exotic bases, the following syntax can be used:

         /* add a base 36 constant */
         %% mpz_t x2 = x1 + (mpz_t) const ("ag12", 36);

The string and base arguments are passed directly to mpX_set_str(). The type is derived from a preceding cast if present, otherwise the default type is used (so in the previous example, the cast is not really needed). Note that this is the only way to introduce mpf_t or double constants in an mpq_t or mpz_t body.


Next: , Previous: Constants, Up: GMPS expressions

5.5 Function calls

GMPS supports GMP function calls. Use gmpc -fdump-prototypes to see the complete list of supported functions. This list should contain all functions that can be called using the types that GMPS supports: mpq_t, mpz_t, mpf_t, double, unsigned long int, long int and int (void return values are treated specially). This excludes functions like void mpz_random (mpz_t rop, mp_size_t max_size), because GMPS does not know how to handle the mp_size_t parameter.

GMP functions without a return value behave as if they do have a return value. The void return value is replaced with the first parameter. This makes them easier to use in expressions.

         r_new = mpf_sqrt(r, x*x + y*y) + r_old;

Here, the square root is stored in r and also used in the addition.

Furthermore, it is allowed to omit the first parameter altogether, if it is pass-by-reference. GMPS implicitly assumes it is an output variable. So in the previous example, if r is not needed, the following would be equivalent:

         r_new = mpf_sqrt(x*x + y*y) + r_old;

Next: , Previous: Function calls, Up: GMPS expressions

5.6 Arrays

GMPS does not treat arrays specially. Variable references may have trailing array index expressions. They are simply copied to the output file.

In this example, it is assumed that the arrays A, B and C have been set up beforehand. The [i] subscripts will be copied verbatim to the output.

         %% import mpq_t A, B, C;
         for (i=0; i<N; i++) {
             %% mpq_t
             %%   A[i] = f * B[i] + (1-f) * C[i];
         }

Arrays must be imported, and since gmpc does not know anything about array dimensions, they must be imported as scalars. In GMPS, A[1] and A[1][i+j] have the same type as A.

Note: GMPS does not support nested [] brackets, so things like A[c[i,j]][k] will be rejected by gmpc.


Previous: Arrays, Up: GMPS expressions

5.7 Evaluation order

In GMPS the operator precedence is the same as in C. This means that in many cases the evaluation order is predictable, at least to a degree that makes sense mathematically. So a+b*c is equivalent to a+(b*c), or maybe (c*b)+a but never (a+b)*c. Especially if a, b and c have different types, they may be shuffled around to better fit the available GMP functions.

Increment and decrement operations are treated as side effects, which are guaranteed to have been fully evaluated at certain points in an expression. In GMPS these points are:

  1. At the end of a full expression, i.e. at the semicolon or closing brace.
  2. Directly before a function call, after the arguments have been evaluated.
  3. Between the evaluation of the left and right operands of the boolean operators && and ||.

This is essentially the subset of C sequence points that are relevant to GMPS.


Next: , Previous: GMPS expressions, Up: Top

6 Complete example

This section shows an annotated example of a sine function. The source file, sine.gmpc, can be found in the tests directory of the gmpc distribution.

First, the usual #include statements are needed.

     #include <stdio.h>
     #include <gmp.h>
     
     %% static declarations;

We want gmpc to create static declarations, directly after the #include statements, and before the definition of the mpf_sine_raw function.

     
     /* raw sine, first quadrant only, using Taylor */
     void mpf_sine_raw(mpf_t sum, mpf_t x)
     {
         %% import mpf_t sum, x;

The function parameters must be imported, since we do not want gmpc to create init and cleanup code for them.

         long int n_narrowing = 3;
         long int i;
         long int i_fact = 1;
         long int sign = 1;
         %% import long int i_fact, sign;

We will manipulate these variables in C, so we define them in C and then import the variables that are used in the formulas into GMPS.

         int stop = 0;
         %% import int stop;
         %% mpf_t abs_tol = x * 1e-50;

stop should be a boolean with function scope, so we declare it in our C source and then import it. abs_tol is not defined, so gmpc will create it for us, with file scope.

         /* divide angle by 5 a few times, undo later using */
         /* sin(5*x) = 16*sin^5(x)-20*sin^3(x)+5*sin(x) */
     
         for (i=0; i<n_narrowing; i++) {
             %% mpf_t {
             %%     x *= 1/5;
             %%     abs_tol *= 1/5;
             %% }
         }
     
         /* init Taylor, i = 1 */
     
         %% mpf_t {
         %%     sum = x;
         %%     xi = x;
         %%     x2 = x * x;
         %% }

We introduce some more undefined variables, which will be taken care of by gmpc.

     
         /* Taylor series expansion, i = 3, 5, 7, ... */
     
         for (i=3; !stop; i += 2) {
             sign *= -1;
             i_fact *= (i-1) * i;
             %% mpf_t {
             %%     xi *= x2;
             %%     term = sign * xi / i_fact;
             %%     sum += term;
             %%     stop = mpf_abs(term) < abs_tol;
             %% }
         }
     
         /* Blow up angle again */
     
         for (i=0; i<n_narrowing; i++) {
             %% mpf_t {
             %%     sum2 = sum * sum;
             %%     sum *= 5 + sum2 * (-20 + 16 * sum2);
             %% }
         }
     }
     

We need a main to test our function.

     int main(void)
     {
         mpf_set_default_prec (100);
         %% init;

Initialisation code will be inserted here.

         %% mpf_t { test_sine = 0; test_arg = 0.5; }

Again, let gmpc handle these variables.

         gmp_printf("mpf_sine_raw(%.Ff) = ", test_arg);
         mpf_sine_raw(test_sine, test_arg);
         gmp_printf("%.Ff\n", test_sine);
         return 0;
     }

This completes sine.gmpc. gmpc is invoked as follows:

     gmpc -Wall -o sine.c sine.gmpc

After a lot of warnings, a file sine.c is produced.

     sine.gmpc:18:14: warning: undefined variable 'abs_tol'
     sine.gmpc:34:12: warning: undefined variable 'xi'
     sine.gmpc:35:12: warning: undefined variable 'x2'
     sine.gmpc:45:16: warning: undefined variable 'term'
     sine.gmpc:55:16: warning: undefined variable 'sum2'
     sine.gmpc:65:16: warning: undefined variable 'test_sine'
     sine.gmpc:65:31: warning: undefined variable 'test_arg'
     sine.gmpc: warning: missing cleanup section

The resulting sine.c can be compiled:

     gcc -lgmp sine.c

And the result of all this is:

     ./a.out
     mpf_sine_raw(0.5) = 0.4794255386042030002732879352155713880842

For the sake of completeness, here is the generated sine.c:

     #line 1 "sine.gmpc"
     #include <stdio.h>
     #include <gmp.h>
     
     #line 6 "sine_example.c"
     static mpf_t abs_tol;
     static mpf_t gmpscf000;
     static mpf_t gmpscf001;
     static mpf_t gmpscf002;
     static mpf_t gmpscf003;
     static mpf_t gmpscf004;
     static mpf_t gmpscf005;
     static mpf_t gmpscf006;
     static mpf_t gmpstf000;
     static mpf_t sum2;
     static mpf_t term;
     static mpf_t test_arg;
     static mpf_t test_sine;
     static mpf_t x2;
     static mpf_t xi;
     #line 5 "sine.gmpc"
     
     /* raw sine, first quadrant only, using Taylor */
     void mpf_sine_raw(mpf_t sum, mpf_t x)
     {
         long int n_narrowing = 3;
         long int i;
         long int i_fact = 1;
         long int sign = 1;
         int stop = 0;
     
     #line 33 "sine_example.c"
         mpf_mul (abs_tol, x, gmpscf000);
     #line 19 "sine.gmpc"
     
         /* divide angle by 5 a few times, undo later using */
         /* sin(5*x) = 16*sin^5(x)-20*sin^3(x)+5*sin(x) */
     
         for (i=0; i<n_narrowing; i++) {
     #line 41 "sine_example.c"
             mpf_mul (x, x, gmpscf001);
             mpf_mul (abs_tol, abs_tol, gmpscf001);
     #line 28 "sine.gmpc"
         }
     
         /* init Taylor, i = 1 */
     
     #line 49 "sine_example.c"
         mpf_set (sum, x);
         mpf_set (xi, x);
         mpf_mul (x2, x, x);
     #line 37 "sine.gmpc"
     
         /* Taylor series expansion, i = 3, 5, 7, ... */
     
         for (i=3; !stop; i += 2) {
             sign *= -1;
             i_fact *= (i-1) * i;
     #line 60 "sine_example.c"
             mpf_mul (xi, xi, x2);
             mpf_set_si (term, sign);
             mpf_mul (term, xi, term);
             mpf_set_si (gmpstf000, i_fact);
             mpf_div (term, term, gmpstf000);
             mpf_add (sum, sum, term);
             mpf_abs (gmpstf000, term);
             stop = mpf_cmp (gmpstf000, abs_tol);
             stop = ((stop) < (0));
     #line 49 "sine.gmpc"
         }
     
         /* Blow up angle again */
     
         for (i=0; i<n_narrowing; i++) {
     #line 76 "sine_example.c"
             mpf_mul (sum2, sum, sum);
             mpf_mul (gmpstf000, gmpscf002, sum2);
             mpf_add (gmpstf000, gmpscf003, gmpstf000);
             mpf_mul (gmpstf000, sum2, gmpstf000);
             mpf_add (gmpstf000, gmpscf004, gmpstf000);
             mpf_mul (sum, sum, gmpstf000);
     #line 58 "sine.gmpc"
         }
     }
     
     int main(void)
     {
         mpf_set_default_prec (100);
     #line 90 "sine_example.c"
         mpf_init (abs_tol);
         mpf_init (gmpscf000);
         mpf_set_str (gmpscf000, "0.1e-49", 10);
         mpf_init (gmpscf001);
         mpf_set_str (gmpscf001, "0.2e0", 10);
         mpf_init (gmpscf002);
         mpf_set_str (gmpscf002, "0.16e2", 10);
         mpf_init (gmpscf003);
         mpf_set_str (gmpscf003, "-0.2e2", 10);
         mpf_init (gmpscf004);
         mpf_set_str (gmpscf004, "0.5e1", 10);
         mpf_init (gmpscf005);
         mpf_set_str (gmpscf005, "0.e0", 10);
         mpf_init (gmpscf006);
         mpf_set_str (gmpscf006, "0.5e0", 10);
         mpf_init (gmpstf000);
         mpf_init (sum2);
         mpf_init (term);
         mpf_init (test_arg);
         mpf_init (test_sine);
         mpf_init (x2);
         mpf_init (xi);
         mpf_set (test_sine, gmpscf005);
         mpf_set (test_arg, gmpscf006);
     #line 66 "sine.gmpc"
         gmp_printf("mpf_sine_raw(%.Ff) = ", test_arg);
         mpf_sine_raw(test_sine, test_arg);
         gmp_printf("%.Ff\n", test_sine);
         return 0;
     }

Note how gmpc inserts #line statements, so C compilers and debuggers can refer directly to the .gmpc file.


Next: , Previous: Complete example, Up: Top

Appendix A GMPS grammar

     program:
              statement_list <<EOF>>
            | <<EOF>>
            ;
     
     statement_list:
              statement
            | statement_list statement
            ;
     
     statement:
              "init" ";"
            | decl_statement ";"
            | var_statement ";"
            | body_statement
            | "cleanup" ";"
            | {CSOURCE}
            ;
     
     decl_statement:
              "declarations"
            | "static" "declarations"
            ;
     
     var_statement:
              "import" any_type  ident_list
            | "var" any_type     ident_list
            ;
     
     ident_list:
              {IDENT}
            | ident_list "," {IDENT}
            ;
     
     body_statement:
              "body" any_type
                 exp_arg
            |          any_type
                 exp_arg
            ;
     
     exp_arg:
              exp ";"
            | "{" exp_list "}"
            | "{" exp_list ";" "}"
            ;
     
     exp_list:
              exp
            | exp_list ";" exp
            ;
     
     arg_list:
              exp
            | arg_list "," exp
            ;
     
     exp:
              {OCTINT}|{FLOAT}|{HEXINT}|{BININT}
            | ident
            | exp "+" exp
            | exp "-" exp
            | exp "*" exp
            | exp "/" exp
            | exp "%" exp
            | exp "<<" exp
            | exp ">>" exp
            | exp "==" exp
            | exp "!=" exp
            | exp "<" exp
            | exp "<=" exp
            | exp ">" exp
            | exp ">=" exp
            | exp "&&" exp
            | exp "||" exp
            | exp "&" exp
            | exp "|" exp
            | exp "^" exp
            | "-" exp
            | "+" exp
            | "!" exp
            | "~" exp
            | "(" exp ")"
            | exp "=" exp
            | exp "<<="|">>="|[\-%+/*&^|~]"=" exp
            | "++" exp
            | "--" exp
            | exp "++"
            | exp "--"
            | {IDENT} "(" arg_list ")"
            | cast
                     exp
     
            | const_escape
            ;
     
     cast:
              "(" any_type ")"
            ;
     
     any_type:
              long_int
            | "signed"
            | "signed" long_int
            | "unsigned"
            | "unsigned" long_int
            | "double"
            | "mpq_t"
            | "mpz_t"
            | "mpf_t"
            | "int"
            ;
     
     long_int:
              "long"
            | "long" "int"
            ;
     
     const_escape:
              "const" "(" \"[^"]*\" ","
                 {OCTINT}|{FLOAT}|{HEXINT}|{BININT} ")"
     
            ;
     
     ident:
              {IDENT}
            | {IDENT} array_index_list
            ;
     
     array_index_list:
              "["[^]]*"]"
            | array_index_list "["[^]]*"]"
            ;
     

Previous: GMPS grammar, Up: Top

Index