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    /// What the unit's `#pragma comment` lines ask the linker for, in the order they were
71    /// written.
72    pub comments: Vec<crate::Comment>,
73}
74
75impl Parsed {
76    /// Whether anything was reported at an error severity.
77    #[must_use]
78    pub fn failed(&self) -> bool {
79        self.diagnostics.iter().any(|d| d.severity.is_fatal())
80    }
81}
82
83/// The parser.
84#[derive(Debug)]
85pub struct Parser<'a> {
86    pub(crate) cursor: Cursor<'a>,
87    pub(crate) tokens: &'a Tokens,
88    pub(crate) scopes: Scopes,
89    pub(crate) errors: Errors,
90    pub(crate) ast: Ast,
91    pub(crate) cx: Context<'a>,
92    /// How many brackets are open, for [`MAX_NESTING`].
93    depth: usize,
94    /// Whether the nesting cap has already been reported, since reporting it at every level of
95    /// a thousand deep nesting is a thousand copies of the same message.
96    too_deep: bool,
97    /// The `#pragma pack` lines read so far, which is in `pack.rs` with the code that reads them.
98    pub(crate) packs: crate::pack::Packs,
99    /// What the `#pragma comment` lines read so far ask for.
100    pub(crate) comments: Vec<crate::Comment>,
101}
102
103impl<'a> Parser<'a> {
104    /// A parser over `tokens`.
105    #[must_use]
106    pub fn new(tokens: &'a Tokens, cx: Context<'a>) -> Parser<'a> {
107        let mut scopes = Scopes::new();
108        for &name in cx.type_names {
109            scopes.declare(name, IdentKind::Typedef);
110        }
111        Parser {
112            cursor: Cursor::new(&tokens.tokens),
113            tokens,
114            scopes,
115            errors: Errors::new(cx.error_limit),
116            ast: Ast::new(),
117            cx,
118            depth: 0,
119            too_deep: false,
120            packs: crate::pack::Packs::default(),
121            comments: Vec::new(),
122        }
123    }
124
125    /// The tree and the diagnostics, once the parse is over.
126    #[must_use]
127    pub fn finish(self) -> Parsed {
128        Parsed { ast: self.ast, diagnostics: self.errors.finish(), comments: self.comments }
129    }
130
131    /// Reports an error at `span`.
132    pub(crate) fn error(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
133        self.errors.push(Diagnostic::error(message, span).with_code(code));
134    }
135
136    /// Reports a warning at `span`.
137    pub(crate) fn warn(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
138        self.errors.push(Diagnostic::warning(message, span).with_code(code));
139    }
140
141    /// Reports a warning that only `-pedantic` asks for.
142    pub(crate) fn pedantic(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
143        if self.cx.pedantic {
144            self.warn(code, message, span);
145        }
146    }
147
148    /// Whether the parse should stop, because the error limit was reached.
149    pub(crate) fn stopped(&self) -> bool {
150        self.errors.stopped()
151    }
152
153    /// How a token is named in a diagnostic.
154    pub(crate) fn describe(&self, token: Token) -> String {
155        match token.kind {
156            TokenKind::Eof => "end of file".to_string(),
157            TokenKind::Punct(punct) => format!("`{}`", punct.as_str()),
158            TokenKind::Keyword(word) => format!("`{}`", word.as_str()),
159            TokenKind::Ident => {
160                format!("`{}`", self.cx.interner.resolve(Symbol::from_raw(token.value)))
161            }
162            TokenKind::Int => "an integer constant".to_string(),
163            TokenKind::Float => "a floating constant".to_string(),
164            TokenKind::Char => "a character constant".to_string(),
165            TokenKind::Str => "a string literal".to_string(),
166        }
167    }
168
169    /// Consumes `punct`, or reports that it is missing without consuming anything.
170    ///
171    /// The message points at the end of the previous token rather than at the token that turned
172    /// up, because a missing semicolon belongs at the end of the line it is missing from and not
173    /// at the start of the next one.
174    pub(crate) fn expect_punct(&mut self, punct: Punct) -> bool {
175        if self.cursor.eat_punct(punct) {
176            return true;
177        }
178        let found = self.describe(self.cursor.current());
179        let message = format!("expected `{}`, found {found}", punct.as_str());
180        let at = if punct == Punct::Semi { self.cursor.prev_end() } else { self.cursor.span() };
181        self.error("E0400", message, at);
182        false
183    }
184
185    /// Consumes `keyword`, or reports that it is missing.
186    pub(crate) fn expect_keyword(&mut self, keyword: Keyword) -> bool {
187        if self.cursor.eat_keyword(keyword) {
188            return true;
189        }
190        let found = self.describe(self.cursor.current());
191        let message = format!("expected `{}`, found {found}", keyword.as_str());
192        self.error("E0400", message, self.cursor.span());
193        false
194    }
195
196    /// Consumes an identifier and gives back its symbol and span.
197    pub(crate) fn expect_ident(&mut self) -> Option<(Symbol, Span)> {
198        if let Some(name) = self.cursor.current().ident() {
199            let span = self.cursor.span();
200            self.cursor.bump();
201            return Some((name, span));
202        }
203        let found = self.describe(self.cursor.current());
204        self.error("E0401", format!("expected an identifier, found {found}"), self.cursor.span());
205        None
206    }
207
208    /// A string literal, copied out of the token stream and into the tree.
209    ///
210    /// The literal rather than the expression: an `asm` template and a `static_assert` message
211    /// are strings in the grammar and not operands, so nothing is allowed to concatenate an
212    /// identifier onto one or take its address.
213    pub(crate) fn string_literal(&mut self) -> Option<StrId> {
214        let token = self.cursor.current();
215        if token.kind == TokenKind::Str {
216            self.cursor.bump();
217            let literal = self.tokens.strings[token.value as usize].clone();
218            return Some(self.ast.add_string(literal));
219        }
220        let found = self.describe(token);
221        self.error("E0409", format!("expected a string literal, found {found}"), token.span);
222        None
223    }
224
225    /// Opens a bracket, and reports the one time the nesting is too deep to continue.
226    ///
227    /// A caller that is refused must not recurse. It steps over the token that would have
228    /// opened the bracket and produces a poisoned node, which is what keeps the outer loops
229    /// making progress rather than meeting the same token again.
230    #[must_use]
231    pub(crate) fn enter(&mut self) -> bool {
232        if self.depth >= MAX_NESTING {
233            if !self.too_deep {
234                self.too_deep = true;
235                self.error(
236                    "E0402",
237                    format!("brackets nested more deeply than {MAX_NESTING} levels"),
238                    self.cursor.span(),
239                );
240            }
241            return false;
242        }
243        self.depth += 1;
244        true
245    }
246
247    /// Closes a bracket opened by [`Parser::enter`].
248    pub(crate) fn leave(&mut self) {
249        self.depth -= 1;
250    }
251
252    /// Adds an expression to the tree.
253    pub(crate) fn add_expr(&mut self, expr: Expr, span: Span) -> ExprId {
254        self.ast.expr(expr, span)
255    }
256
257    /// Adds a statement to the tree.
258    pub(crate) fn add_stmt(&mut self, stmt: Stmt, span: Span) -> StmtId {
259        self.ast.stmt(stmt, span)
260    }
261
262    /// Adds a declaration to the tree.
263    pub(crate) fn add_decl(&mut self, decl: Decl, span: Span) -> DeclId {
264        self.ast.decl(decl, span)
265    }
266
267    /// An expression node standing in for one that did not parse.
268    pub(crate) fn poison_expr(&mut self, span: Span) -> ExprId {
269        self.ast.expr(Expr::Error, span)
270    }
271
272    /// A statement node standing in for one that did not parse.
273    pub(crate) fn poison_stmt(&mut self, span: Span) -> StmtId {
274        self.ast.stmt(Stmt::Error, span)
275    }
276
277    /// A declaration node standing in for one that did not parse.
278    pub(crate) fn poison_decl(&mut self, span: Span) -> DeclId {
279        self.ast.decl(Decl::Error, span)
280    }
281
282    /// The span from `start` to the end of the token before the current one.
283    pub(crate) fn span_from(&self, start: Span) -> Span {
284        start.to(self.cursor.prev_end())
285    }
286}