On Dienstag, 8. Juli 2008, Andrew Johnson wrote:
> On Tuesday 08 July 2008 02:16:12 Bernd Schoeneburg wrote:
> > The additional field attribute (copy to partner ioc: yes/no) is not
> > implemented in this way. I have no good idea how to decide this without
> > base modification.
>
> The last time we talked about that you hadn't actually set that attribute
> on any of the base record types, so I wasn't sure whether you still need
> it or not. I don't think it would be too hard to provide the attribute
> information to the CCE outside of the original DBD file, although
> admittedly it might complicate the code a bit.
The problem might be solved by suitable generalization. I am thinking about
extensible syntax with pluggable handlers, an idea I've been pondering for
a long time. This would have a wide range of possible applications,
including pluggable field properties like 'copy_to_partner' as proposed by
Bernd, while retaining complete backward compatibility. Let me explain what
I mean.
Currently all syntax for db and dbd files is hard-coded into the parser.
That, however, need not be the case. The grammar itself is very simple and
regular: there is exactly one aggregate syntactical structure which I will
call <definition>. A definition consists of a <head> of the form:
<keyword> (<argument>,...)
optionally followed by a <body>:
{ <definition> ... }
where an <argument> is either a number, or a quoted string (unrestricted
charset), or a bareword (restricted charset). The top-level is simply a
sequence of definitions (like the inside of a body).
Let me coin the term 'construct' for the several (semantically different)
kinds of definitions: some are top-level, such as menu definitions,
recordtype definitions, record instance definitions, etc., some are nested
inside other definitions, such as a field description inside a recordtype,
which is different from a field definition inside a record instance. Each
construct has a unique keyword, but is in turn uniqely determined only by
its keyword /and/ the sequence of constructs it appears nested in. By
induction, the sequence of keywords (of constructs) leading to a definition
(including its own one) determines the construct. For instance, the
top-level construct "menu definition" can be referenced by the
(one-element) keyword sequence [menu], while the construct "menu property
of a field definition" is referenced by the keyword sequence
[recordtype,field,menu].
Now the basic idea is that we could allow /syntax-plugins/ to define new
constructs and also register interest in existing ones. Each plugin gets
called by the parser exactly once for each definition the parser encounters
that matches a declared interest, passing the values of the parsed
arguments. There is no need (and thus no way) for the plugin to do any
parsing itself (apart from interpreting the argument strings): descending
deeper into a possible body containing nested definitions is done by the
parser. If a new construct shall contain sub-constructs, these must be
registered separately.
A minimal API could be:
--8<-------------------------------------------------------------
typedef enum { syntaxPlugOk, syntaxPlugError } syntaxPlugResult;
typedef syntaxPlugResult syntaxPlugOnPush(int argc, char **argv);
typedef syntaxPlugResult syntaxPlugOnPop(void);
syntaxPlugResult syntaxPlugRegister(int keyc, char **keyv,
syntaxPlugOnPush *onPush, syntaxPlugOnPop *onPop);
--8<-------------------------------------------------------------
The onPush handler gets called when the parser encounters a definition head
matching the registered interest (keyword sequence); the onPop handler gets
called after the body has been parsed as well (or immediately afterwards if
there is no body). The onPop handler enables the plugin to do proper
book-keeping about how a sub-definition is nested inside another
definition. It may be set to NULL.
For instance, the redundancy plugin would register interest for these
constructs:
- [recordtype]
- [recordtype, field]
- [recordtype, field, copy_to_partner]
It should be obvious how the plugin implements the onPush and onPop handlers
for these constructs (the onPop handler for the third construct can be
NULL, of course as it has no body).
One side note is in order here: underlying this extremely simple API is the
(as yet unspoken) assumption that we can simply and safely /ignore/ any
definitions -- including nested ones -- for which no syntax plugin has been
registered. The parser itself accepts any input that consists of
syntactically valid definitions as defined above. This is important for
compatibility between plugins. For instance, a dbd file for one IOC will be
a (syntactically) valid dbd file for any other IOC, regardless of what
plugins (if any) are installed on both IOCs. It is perfectly ok for a
plugin to 'eaves-drop' on some other plugin's (or on built-in) constructs.
Ownership of keywords is best managed by a community process, such as a
listing plugins and their (new) keywords on the EPICS wiki. This model has
the very nice feature of always retaining not only backwards, but also
forward compatibility, i.e. new files, supporting new extensions can still
be used unchanged on IOCs w/o the new plugin.
Alternatively, a stricter checking policy can be implemented, too, by
extending the API with a construct creation call, and demanding that a new
construct must always be created before handlers for it can be registered.
This, however, makes it harder for plugins to engage in mutual co-operation
(first both must create their constructs, then both register interest in
the other's constructs).
As to implementation, the parser itself becomes rather simpler. It must
merely keep a tree-like data structure representing the registered (and the
built-in) constructs, and to each construct a list of onPush handlers and
onPop handlers. It must also maintain a stack of constructs (represented as
pointers into the construct tree) to decide which handlers to call at each
step.
I am almost of a mind to start hacking on a prototype implementation...
Cheers
Ben
- Replies:
- Re: IOC Redundancy in R3.14.10 Andrew Johnson
- References:
- IOC Redundancy in R3.14.10 Schoeneburg, Bernd
- Re: IOC Redundancy in R3.14.10 Bernd Schoeneburg
- Re: IOC Redundancy in R3.14.10 Andrew Johnson
- Navigate by Date:
- Prev:
Re: IOC Redundancy in R3.14.10 Andrew Johnson
- Next:
Re: IOC Redundancy in R3.14.10 Schoeneburg, Bernd
- Index:
2002
2003
2004
2005
2006
2007
<2008>
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Re: IOC Redundancy in R3.14.10 Andrew Johnson
- Next:
Re: IOC Redundancy in R3.14.10 Andrew Johnson
- Index:
2002
2003
2004
2005
2006
2007
<2008>
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|