From c9b820ef5fca7d30e8f075409cc6ad4ff36fbd79 Mon Sep 17 00:00:00 2001 From: "benjamin.franksen" <benjamin.franksen@helmholtz-berlin.de> Date: Thu, 14 Mar 2013 11:26:34 +0000 Subject: [PATCH] docs: expanded reference section on C compatibility features - make clear that you can reference foreign entities directly in action statements w/o recourse to escape syntax - explain why and how to avoid #include and other CPP directives in multi-line escaped code blocks --- documentation/Reference.txt | 109 +++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 26 deletions(-) diff --git a/documentation/Reference.txt b/documentation/Reference.txt index 0e64ad90..60b52cf6 100644 --- a/documentation/Reference.txt +++ b/documentation/Reference.txt @@ -88,7 +88,7 @@ any) at the given line. :token:`file_name` must be a single string (no automatic string concatenation). -Line markers are typically generated by preprocessors, such as CPP. +Line markers are typically generated by preprocessors, such as *cpp*. .. _StateProgram: @@ -323,7 +323,7 @@ Foreign Entities ~~~~~~~~~~~~~~~~ The pseudo type "foreign" is used to declare any number of C variables -or struct tags or CPP macros that have been defined outside the SNL +or struct tags or *cpp* macros that have been defined outside the SNL program. No warning will be issued if such a variable, struct tag, or macro is used in the program even if warnings are enabled. @@ -1500,8 +1500,7 @@ pvTimeStamp Returns the time stamp for the last :c:func:`pvGet` completion or monitor event for this variable. The SNL compiler does not recognize type epicsTimeStamp. Therefore, variable declarations for this type should be in escaped -C code. This will generate a compiler warning, which can be -ignored or fixed by adding a "foreign" declaration (see `Foreign Entities`_). +C code (see `Escape to C Code`_ and `Foreign Entities`_). Example:: @@ -2014,39 +2013,95 @@ these variable are updated from their globally visible copies. C Compatibility Features ------------------------ +Foreign Variables and Functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can use (reference, call) any exported C variable or function that +is linked to your program. For instance, you may link a C library to +the SNL program and simply call functions from it directly in SNL code. +Note, however, that this is restricted to *SNL action statements* +(:token:`statement`). It is advisable to take care that the C code +generated from your SNL program contains (directly oir via ``#include``) +a valid declaration for such entities, otherwise the C compiler will +not be able to catch type errors (the SNL compiler does not do any +type-checking by itself). For libraries, this is usually done +by adding a line :: + + %%#include "api-of-your-library.h" + +This uses the one-line-escape syntax explained in the next section. + +For historical reasons, *snc* complains with a warning if you use a +foreign variable (or structure tag, or macro) in SNL code (but not for +function calls). This can be suppressed by adding a foreign +declaration (see `Foreign Entities`_). + + Escape to C Code ^^^^^^^^^^^^^^^^ Because the SNL does not support the full C language, C code may be -escaped in the program. The escaped code is not compiled by SNC, -but is passed the C compiler. There are two escape methods -allowed: +escaped in the program. The escaped code is not compiled by *snc*, +but is passed literally to the C compiler. There are two escape +methods allowed: #. Any code between ``%%`` and the next newline character is escaped. Example:: - %% for (i=0; i < NVAL; i++) { + %% for (i=0; i < NVAL; i++) #. Any code between ``%{`` and ``}%`` is escaped. Example:: - %{ - extern float smooth(); - extern LOGICAL accelerator_mode; - }% + %{ + extern float smooth(); + extern LOGICAL accelerator_mode; + }% + + Note that text appearing on the same line after ``%{`` and + before ``}%`` also belongs to the literal code block. + +A variable (or struct tag or macro) declared in escaped C code is +foreign to the SNL, just as if it were declared in C code extern to +the SNL program and its use will give a warning if no foreign +declaration preceeds it. + + +Preprocessor Directives +~~~~~~~~~~~~~~~~~~~~~~~ -If you are using the C pre-processor prior to compiling with *snc*, -and you wish to defer interpretation of a preprocessor directive, -then you should use the form:: +A very common pitfall is the use of preprocessor directives, such as +``#include``, in multi-line literal C code blocks in conjunction +with using the preprocessor on the unprocessed SNL code (which +happens by the default with the standard build rules if the name of +the source file has the ``.st`` extension). - %%#include <ioLib.h> - %%#include <abcLib.h> +For instance with :: -Any variable declared in escaped C code and used in SNL code will -be flagged with a warning message by the SNC. However, it will be -passed on to the C compiler correctly. + %{ + #include <abcLib.h> + /* ... */ + }% + +the header file will be included *before* the SNL compiler parses +the program, which is most probably not what you wanted to happen +here. For instance, +if the header contains macro definitions, these will not be in effect +when the rest of the C code block gets compiled. + +You can defer defer interpretation of a preprocessor directive until +after *snc* has compiled the code to C, by ensuring that some extra +non-blank characters appear in front of the ``#`` sign, so *cpp* does +not recognize the directive. For instance :: + + %%#include <abcLib.h> -C Functions within the State Program -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +or :: + + %{#include <abcLib.h>}% + + +Defining C Functions within the Program +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Escaped C code can appear in many places in the SNL program. But only code that appears at the top level, i.e. outside any SNL code block will @@ -2064,17 +2119,18 @@ placed there; this means either inside the definitions section It matters where the function is defined: if it appears at the end of the program, it can see all the variable and type definitions generated -by the SNL compiler, so if your C function acesses a global SNL variable, +by the SNL compiler, so if your C function accesses a global SNL variable, you must place its definition at the end. However, this means that the generated code for the SNL program does not see the C function definition, so you might want to place a separate prototype for the function in the definitions section (i.e. before the state sets). -Note that you can *call* any C function from anywhere in the SNL program +Remember that you can *call* any C function from anywhere in the SNL program without escaping. You can also link the SNL program to C objects or libraries, so the only reason to put C function definitions inside the SNL program is if your function accesses global SNL variables. + Calling pvGet etc. from C ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -2100,12 +2156,13 @@ as well as additional supporting macros and type definitions can be found in the header file ``seqCom.h``. This header file is always included by the generated C code. + .. _reentrant option: Variable Modification for Reentrant Option ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If the reentrant option (:option:`+r`) is specified to SNC then all +If the reentrant option (:option:`+r`) is specified to *snc* then all variables are made part of a structure. Suppose we have the following top-level declarations in the SNL program:: @@ -2131,7 +2188,7 @@ Reference to variable ``sw1`` is made as :: pVar->sw1 -This conversion is automatically performed by the SNC for all SNL +This conversion is automatically performed by the *snc* for all SNL statements, but you will have to handle escaped C code yourself. .. note:: -- GitLab