3 Parsing and Reading C
(require c/parse) | package: c-utils |
Each of the parsing operations takes three optional keyword arguments. The #:typedef argument takes a list of type names to bind as though by typedef in the parser’s initial environment. The #:source argument is used to identify the source of the input in the source location information. The #:offset argument is used as the base offset of source location information. This is useful for parsing source extracted from the middle of a file or input port. If this argument is ommitted or #f, the parsed text is assumed to appear at the beginning of the input source.
3.1 Parsing
procedure
(parse-program in [ #:typedef typedef #:source source #:offset offset]) → (listof decl?) in : (or/c input-port? string? path?) typedef : (or/c (listof symbol?) #f) = #f source : any = #f offset : (or/c position? #f) = #f
procedure
(parse-declaration in [ #:typedef typedef #:source source #:offset offset]) → decl? in : (or/c input-port? string? path?) typedef : (or/c (listof symbol?) #f) = #f source : any = #f offset : (or/c position? #f) = #f
procedure
(parse-statement in [ #:typedef typedef #:source source #:offset offset]) → stmt? in : (or/c input-port? string? path?) typedef : (or/c (listof symbol?) #f) = #f source : any = #f offset : (or/c position? #f) = #f
procedure
(parse-expression in [ #:typedef typedef #:source source #:offset offset]) → expr?? in : (or/c input-port? string? path?) typedef : (or/c (listof symbol?) #f) = #f source : any = #f offset : (or/c position? #f) = #f
procedure
(parse-type-expression in [ #:typedef typedef #:source source #:offset offset]) → type? in : (or/c input-port? string? path?) typedef : (or/c (listof symbol?) #f) = #f source : any = #f offset : (or/c position? #f) = #f
3.2 Embedding C in Scheme
See Scribble: The Racket Documentation Tool for more information about Scribble.
This library includes macros for embedding C source in Scheme to be parsed at compile time. These macros are designed to work with the Scribble @-reader to make this embedding convenient.
The following example defines a list of C declaration nodes, parsed at compile time and bound at runtime to decls:
#lang at-exp scheme/base ; ... (define decls @program[#:typedef (word)]{ struct tm { word tm_sec; word tm_min; word tm_hour; word tm_mday; word tm_mon; word tm_year; word tm_wday; word tm_yday; word tm_isdst; }; })
Notice the use of the at-exp language to add @-reader support to the specified scheme/base language.
3.2.1 Scribble Reader
The Scribble @-reader does not itself recognize C syntax; it simply treats free-form text enclosed between { } pairs as string literals. It does match delimiters such as braces, parentheses and brackets, however, which works well with the syntax of C.
The special forms defined in this library work in conjunction with the Scribble reader to allow embedding C as string literals. The reader simply determines the end of the input, and parsing occurs as part of macro expansion.
The forms defined in this library accept only string literals, so in particular nested @-expressions are disallowed.
Since the syntax of C requires parsers to maintain a type environment to distinguish variable names and type names (as bound by typedef), all type names must be declared before they are used. For convenience, each of the special forms in this library accepts an optional #:typedef argument to pre-declare type names.
3.2.2 Avoid Using Here Strings
Technically, it is possible to use the special forms in this library without the Scribble reader by using here strings instead. However, the library is unable to extract accurate source location information with here strings, so this is not recommended.
3.2.3 Embedding C
syntax
(declaration #:typedef (type-id ...) src-string ...+)
(declaration src-string ...+)
syntax
(expression #:typedef (type-id ...) src-string ...+)
(expression src-string ...+)
syntax
(type-expression #:typedef (type-id ...) src-string ...+)
(type-expression src-string ...+)
3.3 Including C Externally
procedure
→ (any input-port? -> (or/c (listof decl?) eof-object?)) typedef : (listof symbol?) = '()
Using include/reader, this makes it relatively convenient to include C source code from an external file:
(require scheme/include (for-syntax scheme/base) (for-syntax c/parse)) ; ... (define fnord.h (include/reader "fnord.h" (make-program-reader #:typedef '(BOOL WORD UINT32))))
Notice that the relevant bindings must be available in the transformer environment in order to apply make-program-reader in the expansion-time argument to include/reader.