Skip to main content

rucc_parse/
parser.rs

1//! The parser itself: the state every production shares, and the helpers they all use.
2//!
3//! Design: `spec/06-lexer-and-parser.md` section 6.3.
4//!
5//! The productions live in the modules beside this one and are written as inherent methods on
6//! [`Parser`], so they read as one recursive descent parser split across files rather than as a
7//! set of functions passing state to each other. What is here is the state, the diagnostics, and
8//! the small number of decisions that more than one production needs.
9
10use rucc_ast::{Ast, Decl, DeclId, Expr, ExprId, Stmt, StmtId, StrId};
11use rucc_base::{Interner, Symbol};
12use rucc_diag::{DEFAULT_ERROR_LIMIT, Diagnostic, Errors, Span};
13use rucc_lex::{Keyword, Punct, Token, TokenKind, Tokens};
14use rucc_session::Std;
15
16use crate::cursor::Cursor;
17use crate::scope::{IdentKind, Scopes};
18
19/// How deeply brackets may nest before the parser gives up.
20///
21/// Recursive descent uses the machine stack for the grammar's nesting, so a file with a
22/// thousand open parentheses is a stack overflow rather than a diagnostic unless something
23/// stops it. The number is clang's `-fbracket-depth` default, which is the one real code has
24/// been measured against, and it is far above anything a human writes and far below anything
25/// that costs the stack more than a fraction of a megabyte.
26pub const MAX_NESTING: usize = 256;
27
28/// Everything the parser needs that is not the tokens.
29#[derive(Debug, Clone, Copy)]
30pub struct Context<'a> {
31    /// The spellings, for the diagnostics that name an identifier.
32    pub interner: &'a Interner,
33    /// The dialect, which decides whether an old-style definition is an error and whether a
34    /// C23 construct is one.
35    pub std: Std,
36    /// Whether the GNU extensions are on, which is `-std=gnu17` rather than `-std=c17`.
37    pub gnu: bool,
38    /// Whether `-pedantic` was given.
39    pub pedantic: bool,
40    /// How many errors to report before stopping, with zero meaning no limit.
41    pub error_limit: usize,
42    /// The names the target declares as types before the file starts, which are the ones
43    /// `rucc_target::TargetInfo::type_names` lists and the file wrote. Declared in the file scope
44    /// rather than made keywords, so a declaration can hide one the way it can in gcc.
45    pub type_names: &'a [Symbol],
46}
47
48impl<'a> Context<'a> {
49    /// A context with the defaults, for a caller that only has an interner to hand.
50    #[must_use]
51    pub fn new(interner: &'a Interner, std: Std) -> Context<'a> {
52        Context {
53            interner,
54            std,
55            gnu: true,
56            pedantic: false,
57            error_limit: DEFAULT_ERROR_LIMIT,
58            type_names: &[],
59        }
60    }
61}
62
63/// What one parse produced.
64#[derive(Debug)]
65pub struct Parsed {
66    /// The tree, which holds poisoned nodes where the source did not parse.
67    pub ast: Ast,
68    /// What went wrong, in the order it was found.
69    pub diagnostics: Vec<Diagnostic>,
70}
71
72impl Parsed {
73    /// Whether anything was reported at an error severity.
74    #[must_use]
75    pub fn failed(&self) -> bool {
76        self.diagnostics.iter().any(|d| d.severity.is_fatal())
77    }
78}
79
80/// The parser.
81#[derive(Debug)]
82pub struct Parser<'a> {
83    pub(crate) cursor: Cursor<'a>,
84    pub(crate) tokens: &'a Tokens,
85    pub(crate) scopes: Scopes,
86    pub(crate) errors: Errors,
87    pub(crate) ast: Ast,
88    pub(crate) cx: Context<'a>,
89    /// How many brackets are open, for [`MAX_NESTING`].
90    depth: usize,
91    /// Whether the nesting cap has already been reported, since reporting it at every level of
92    /// a thousand deep nesting is a thousand copies of the same message.
93    too_deep: bool,
94    /// The `#pragma pack` lines read so far, which is in `pack.rs` with the code that reads them.
95    pub(crate) packs: crate::pack::Packs,
96}
97
98impl<'a> Parser<'a> {
99    /// A parser over `tokens`.
100    #[must_use]
101    pub fn new(tokens: &'a Tokens, cx: Context<'a>) -> Parser<'a> {
102        let mut scopes = Scopes::new();
103        for &name in cx.type_names {
104            scopes.declare(name, IdentKind::Typedef);
105        }
106        Parser {
107            cursor: Cursor::new(&tokens.tokens),
108            tokens,
109            scopes,
110            errors: Errors::new(cx.error_limit),
111            ast: Ast::new(),
112            cx,
113            depth: 0,
114            too_deep: false,
115            packs: crate::pack::Packs::default(),
116        }
117    }
118
119    /// The tree and the diagnostics, once the parse is over.
120    #[must_use]
121    pub fn finish(self) -> Parsed {
122        Parsed { ast: self.ast, diagnostics: self.errors.finish() }
123    }
124
125    /// Reports an error at `span`.
126    pub(crate) fn error(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
127        self.errors.push(Diagnostic::error(message, span).with_code(code));
128    }
129
130    /// Reports a warning at `span`.
131    pub(crate) fn warn(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
132        self.errors.push(Diagnostic::warning(message, span).with_code(code));
133    }
134
135    /// Reports a warning that only `-pedantic` asks for.
136    pub(crate) fn pedantic(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
137        if self.cx.pedantic {
138            self.warn(code, message, span);
139        }
140    }
141
142    /// Whether the parse should stop, because the error limit was reached.
143    pub(crate) fn stopped(&self) -> bool {
144        self.errors.stopped()
145    }
146
147    /// How a token is named in a diagnostic.
148    pub(crate) fn describe(&self, token: Token) -> String {
149        match token.kind {
150            TokenKind::Eof => "end of file".to_string(),
151            TokenKind::Punct(punct) => format!("`{}`", punct.as_str()),
152            TokenKind::Keyword(word) => format!("`{}`", word.as_str()),
153            TokenKind::Ident => {
154                format!("`{}`", self.cx.interner.resolve(Symbol::from_raw(token.value)))
155            }
156            TokenKind::Int => "an integer constant".to_string(),
157            TokenKind::Float => "a floating constant".to_string(),
158            TokenKind::Char => "a character constant".to_string(),
159            TokenKind::Str => "a string literal".to_string(),
160        }
161    }
162
163    /// Consumes `punct`, or reports that it is missing without consuming anything.
164    ///
165    /// The message points at the end of the previous token rather than at the token that turned
166    /// up, because a missing semicolon belongs at the end of the line it is missing from and not
167    /// at the start of the next one.
168    pub(crate) fn expect_punct(&mut self, punct: Punct) -> bool {
169        if self.cursor.eat_punct(punct) {
170            return true;
171        }
172        let found = self.describe(self.cursor.current());
173        let message = format!("expected `{}`, found {found}", punct.as_str());
174        let at = if punct == Punct::Semi { self.cursor.prev_end() } else { self.cursor.span() };
175        self.error("E0400", message, at);
176        false
177    }
178
179    /// Consumes `keyword`, or reports that it is missing.
180    pub(crate) fn expect_keyword(&mut self, keyword: Keyword) -> bool {
181        if self.cursor.eat_keyword(keyword) {
182            return true;
183        }
184        let found = self.describe(self.cursor.current());
185        let message = format!("expected `{}`, found {found}", keyword.as_str());
186        self.error("E0400", message, self.cursor.span());
187        false
188    }
189
190    /// Consumes an identifier and gives back its symbol and span.
191    pub(crate) fn expect_ident(&mut self) -> Option<(Symbol, Span)> {
192        if let Some(name) = self.cursor.current().ident() {
193            let span = self.cursor.span();
194            self.cursor.bump();
195            return Some((name, span));
196        }
197        let found = self.describe(self.cursor.current());
198        self.error("E0401", format!("expected an identifier, found {found}"), self.cursor.span());
199        None
200    }
201
202    /// A string literal, copied out of the token stream and into the tree.
203    ///
204    /// The literal rather than the expression: an `asm` template and a `static_assert` message
205    /// are strings in the grammar and not operands, so nothing is allowed to concatenate an
206    /// identifier onto one or take its address.
207    pub(crate) fn string_literal(&mut self) -> Option<StrId> {
208        let token = self.cursor.current();
209        if token.kind == TokenKind::Str {
210            self.cursor.bump();
211            let literal = self.tokens.strings[token.value as usize].clone();
212            return Some(self.ast.add_string(literal));
213        }
214        let found = self.describe(token);
215        self.error("E0409", format!("expected a string literal, found {found}"), token.span);
216        None
217    }
218
219    /// Opens a bracket, and reports the one time the nesting is too deep to continue.
220    ///
221    /// A caller that is refused must not recurse. It steps over the token that would have
222    /// opened the bracket and produces a poisoned node, which is what keeps the outer loops
223    /// making progress rather than meeting the same token again.
224    #[must_use]
225    pub(crate) fn enter(&mut self) -> bool {
226        if self.depth >= MAX_NESTING {
227            if !self.too_deep {
228                self.too_deep = true;
229                self.error(
230                    "E0402",
231                    format!("brackets nested more deeply than {MAX_NESTING} levels"),
232                    self.cursor.span(),
233                );
234            }
235            return false;
236        }
237        self.depth += 1;
238        true
239    }
240
241    /// Closes a bracket opened by [`Parser::enter`].
242    pub(crate) fn leave(&mut self) {
243        self.depth -= 1;
244    }
245
246    /// Adds an expression to the tree.
247    pub(crate) fn add_expr(&mut self, expr: Expr, span: Span) -> ExprId {
248        self.ast.expr(expr, span)
249    }
250
251    /// Adds a statement to the tree.
252    pub(crate) fn add_stmt(&mut self, stmt: Stmt, span: Span) -> StmtId {
253        self.ast.stmt(stmt, span)
254    }
255
256    /// Adds a declaration to the tree.
257    pub(crate) fn add_decl(&mut self, decl: Decl, span: Span) -> DeclId {
258        self.ast.decl(decl, span)
259    }
260
261    /// An expression node standing in for one that did not parse.
262    pub(crate) fn poison_expr(&mut self, span: Span) -> ExprId {
263        self.ast.expr(Expr::Error, span)
264    }
265
266    /// A statement node standing in for one that did not parse.
267    pub(crate) fn poison_stmt(&mut self, span: Span) -> StmtId {
268        self.ast.stmt(Stmt::Error, span)
269    }
270
271    /// A declaration node standing in for one that did not parse.
272    pub(crate) fn poison_decl(&mut self, span: Span) -> DeclId {
273        self.ast.decl(Decl::Error, span)
274    }
275
276    /// The span from `start` to the end of the token before the current one.
277    pub(crate) fn span_from(&self, start: Span) -> Span {
278        start.to(self.cursor.prev_end())
279    }
280}