Getting Help
To see a list of available commands and options that apply to all commands:
daedalus --help
To see a list of options for a specific command:
daedalus COMMAND --help
Command show-types
To type-check a DaeDaLus specification and see the types of the declarations:
daedalus show-types MyParserSpec.ddl
The command prints information about the types and parsers defined by the given specification. For example:
Types
======
def List a =
union
nil: {}
cons: NonEmptyList a
def NonEmptyList a =
struct
head: a
tail: List a
Parsers and Semantic Values
===========================
def List:
for any type a:
parameter: parser of a
defines: parser of List a
def NonEmptyList:
for any type a:
parameter: parser of a
defines: parser of NonEmptyList a
def Main:
defines: parser of List (uint 8)
The resulting types have the following form:
def ParserName:
parameter: <type A>
parameter: <type B>
...
defines: <type C>
This resembles a C type declaration as follows:
<type C> ParserName(<type A>, <type B>, ...);
The types themselves may be simple types such as integers or arrays, but they
often have the form parser of <type A>
. This indicates that the parameter or
result is a parser, that itself generates semantic values of type A
.
Command run
This command is used to run a DaeDaLus specification using the interpreter:
daedalus run MyParserSpec.ddl --input=input.txt
This command will run the parser defined in MyParserSpec.ddl
on the
input from file input.txt
.
If successful, the resulting semantic value will be shown on stdout
.
Flags
- --input=FILE
Specifies that the input for the parser should be read from the given file. If no
--input
is specified, then the interpreter will run with an empty input.
- --entry=[MODULE.]NAME
Specifies which parser defined by the specification should be executed. If no
--entry
is specified, then the interpreter will run the parser calledMain
.The entry parser should have a fixed type (i.e., it should not be polymorphic) and it should not have any parameters, implicit or explicit.
- --json
Show the parsed semantic valus using a JSON based format.
- --html
Show the parsed semantic value rendered as HTML.
- --core
Use the Core IR interpreter.
- --vm
Use the VM IR interpreter.
Command: compile-hs
To compile a DaeDaLus parser specification to Haskell:
daedalus compile-hs MyParserSpec.ddl --out-dir=some_dir_name
The result is a directory populated with a Haskell module containing
definitions for the parsers and functions defined in the specification.
In addition, the DaeDaLus compiler will generate a sample executable
driver and Cabal package description for easy prototyping. To use the
generated code you’ll have to compile it with the rts-hs
package
provided in this distribution.
Warning
At present the command compile-hs
uses the old Haskell backend which
may go away in future. To use the new backend, which is actively
maintained, please use Template Haskell. If there is demand, we may adapt
the new backend to generate explicit Haskell files, in which case this
command will start using the new backend.
Command: compile-c++
To compile a DaeDaLus package specification C++:
daedalus compile-c++ MyParserSpec.ddl --out-dir=some_dir_name
Generated Files
- The compiled parser is in two files:
main_parser.h
contains the interface to the generated parser, andmain_parser.cpp
contains the implementation of the parser.
In addition, the DaeDaLus compiler will generate a sample executable driver
and Makefile
illustrating how to build the parser and generate Doxygen
documentation. The sample executable expects that the compiled specification
contains a parser named Main
that has a fixed type and no parameters
of any kind—if this is not the case, the sample driver will fail to compile.
The sample executable driver will be generated when:
there is no explicit
--entry
specified, andthere is no custom user state
--user-state
, andthe flag
--lazy-streams
is not enabled
Flags
- --out-dir=DIRECTORY
Save generated files in the given directory. The directory will be created if it does not exist.
- --out-dir-header=DIRECTORY
Save generated header files in the given directory. The directory will be created if it does not exist. If this is not specified, then the headers will be saved in
--out-dir
- --file-root=STRING
Use the given string for the names of the generated parser implementation and header. If not specified this will be
main_parser
.
- --user-namespace=NAMESPACE
Place generated type declarations in the given name space. Note that at present this applies only to generate types. Generated parser entry point always reside in the default namespace. If this is not specified, this will be
User
- --no-error-stack
Disable call stack tracking in errors. Without this option, we generate code that leads to more detailed parse error messaged, at some runtime cost. Adding this flag leads to less detailed parse errors, but some potential performance gain.
- --user-state=SATE_TYPE
Generate a parser where the parser’s state will be extended with some user state of the given type. This is useful in certain situations (e.g., caching of data), but care needs to be taken that updates to this state make sense even when the parsers backtracks.
- --add-include=INCLUDE
Add an additoinal #include to the generated parser header file. Typically, this is used to support custom user state, or integration with an pre-compiled DaeDaLus parser. The parameter should just contain the thing to be incuded (e.g.,
"file.h"
or<file.h>
).
- --entry=[MODULE.]NAME
Declare that the given parser is an entry point for the generated parser. Specifying an entry point will disable the genration of a sample driver executable. The name of the C++ function corresponding to DaeDaLus declaration
F
isparseF
. The entry point should have a fixed type, but MAY have argument.void parseMain ( DDL::ParseError &error , std::vector<T>> &results , DDL::Input input );
If an extry point has arguments, they’ll come after the
input
argument. The entry point returns any parsed semantic values in theresults
vector, there could be multiple results if the grammar is ambiguous. If there are no results (i.e.,results
is empty), thenerror
will contain information about the parser error.
- --inline
Perform agressive inlinining—all parsers that can be inlined will be inlinined at each use site. Sometimes this may improve performance, but sometimes it may reduce it, due to a significant increase in the size of the generate code.
- --inlinine-this=[MODULE.]NAME
Inline uses of a specific parser.
- --extern=MODULE[:NAMESPACE]
Do not generate declarations for the types declared in the given module. This is useful when interfacing with a pre-compiled DaeDaLus parser, which already contains declarations for the given types. Often, this option will be comined with
add-include
to include the declarations of the already compiled code. If a namespace is provided, then uses of types in the given module will be qualified with the given namespace. Otherwise, the default namespaceUser
will be used.
- --lazy-strems
Generate code that uses streams where not all data is available when the parser starts. The generated code uses coroutines, as defined by the
fiber
class fromboost-context
library. If the parser reaches the end of an incomplete data stream, it yileds to another coroutine which should either provide more data or terminate the stream before resuming the parser. For more details seeddl/stream.h
. The data streams used by the parser are as defined in classDDL::Stream
. The interaction between the data provider and the parser should be done using classDDL::ParserThread
.
Command: dump
It shows the various IR structures of the DaeDaLus compiler. This command is largely for debugging.
- --parsed
Show the results of just parsing a specification. This ensures that a specification is syntactically correct.
- --resolved
Show the results of name resultion. This associates uses of names with their definitions.
- --tc
Show the results of type-checking. This validates the specification and esnures that parsers are used correctly (e.g. have the correct number of arguments with the correct types). The
dump
command will show this phase, unless another is specified.
- --spec
Show the IR after specialization. Specialization eliminates polymorphism and parsers with other parsers as arguments. This works by generating custom instances of a parser (similar to C++ template expansion). After this pahse, parsers are monomorphic and have only semantic values as parameters.
- --core
Show the Core IR representation. A number of DaeDaLus constructs are desugared into simpler constructs.
- --vm
This is the lowest level IR, which is used to generate code. It is essentially a control flow graph in SSA form, except that instead of using “phi” blocks, basic blocks have parameters.