Skip to main content

Crate rucc_parse

Crate rucc_parse 

Source
Expand description

Recursive descent with a Pratt expression parser, declarators, and error recovery.

Design: spec/06-lexer-and-parser.md. Layer rank 7, see spec/18-package-layout.md.

§Status

The grammar is here: expressions, declaration specifiers, declarators, initializers, statements and declarations, in every dialect from C89 to C23 and with the GNU extensions that real code cannot be read without. parse takes the tokens phase 7 produced and gives back a tree and the diagnostics it collected on the way. What is not here is the printer, so there is no way to turn the tree back into source yet, and there is nothing that checks the tree means anything.

use rucc_base::Interner;
use rucc_lex::{Convert, Keywords, Options, convert, tokenize};
use rucc_parse::{Context, parse};
use rucc_session::Std;
use rucc_target::{TargetInfo, Triple};

let std = Std::C23;
// The keyword table is interned first, before any source is read.
let mut interner = Interner::new();
let keywords = Keywords::new(&mut interner, std, true);
let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().unwrap());

let source = b"int main(void) { return 0; }";
let (pp, _) = tokenize(source, 0, Options::new(), &mut interner);
let cx = Convert { keywords: &keywords, interner: &interner, target: &target,
                   std, pedantic: false };
let (tokens, _) = convert(&pp, &cx);

let parsed = parse(&tokens, Context::new(&interner, std));
assert!(!parsed.failed());
assert_eq!(parsed.ast.top_level().len(), 1);

§What the parser reads

A slice of rucc_lex::Token, which is what phase 7 produces from the preprocessor’s output. Directives are gone by then, adjacent string literals have been joined, constants have been converted, and a spelling no longer means anything. The parser never looks at source text and never asks the lexer a question, which is what makes the typedef decision in scope the only place the ambiguity in C’s grammar is resolved.

§What it builds

A rucc_ast::Ast, which records what was written rather than what it means. Nothing here resolves a name to a declaration, works out a type, folds a constant or desugars anything. A file that parses is not a file that compiles, and keeping the two apart is what lets the printer put back what it was given.

§Where the productions are

Parser holds the state and the helpers, and the productions are inherent methods on it written across six private modules: expressions, specifiers, declarators, initializers, statements and declarations. They are one recursive descent parser split up for reading rather than six things that call each other, so nothing is exported from them.

Every crate in the workspace is published, and publishing implies a promise. This one is tier 3: its Rust API is explicitly unstable and will change without a major version bump. Depend on the rucc binary’s behaviour, not on this.

Re-exports§

pub use crate::cursor::Cursor;
pub use crate::cursor::MAX_LOOKAHEAD;
pub use crate::cursor::Mark;
pub use crate::parser::Context;
pub use crate::parser::MAX_NESTING;
pub use crate::parser::Parsed;
pub use crate::parser::Parser;
pub use crate::recover::Poison;
pub use crate::recover::push_about;
pub use crate::recover::skip_past_declaration;
pub use crate::recover::skip_to_statement_end;
pub use crate::scope::IdentKind;
pub use crate::scope::Scopes;
pub use crate::scope::TagKind;

Modules§

cursor
The token buffer the parser reads.
parser
The parser itself: the state every production shares, and the helpers they all use.
recover
Error recovery: where to resume, and what keeps one error from becoming twenty.
scope
Scopes, and the typedef decision that rests on them.

Constants§

MILESTONE
The milestone in spec/17-milestones.md that fills this crate in.

Functions§

parse
Parses a translation unit.