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