Skip to content
This repository has been archived by the owner on Jun 3, 2021. It is now read-only.

Commit

Permalink
Grammar docs in code blocks and linked to online grammar (#430)
Browse files Browse the repository at this point in the history
* Added ```yacc tags for grammar samples in doc
* Link to online grammar

Co-authored-by: Joshua Nelson <[email protected]>
  • Loading branch information
hdamron17 and Joshua Nelson authored May 13, 2020
1 parent 058dbe1 commit a8159c3
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 16 deletions.
1 change: 0 additions & 1 deletion src/lex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ type LexResult<T = Token> = Result<T, Locatable<LexError>>;
/// You may also find the `warn` and `error` functions in `utils.rs` to be useful.
///
/// Lexer implements iterator, so you can loop over the tokens.
/// ```
#[derive(Debug)]
pub struct Lexer {
location: SingleLocation,
Expand Down
26 changes: 21 additions & 5 deletions src/parse/decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct InternalDeclarator {
}

impl<I: Lexer> Parser<I> {
/// ```yacc
/// external_declaration
/// : function_definition
/// | declaration
Expand All @@ -38,6 +39,8 @@ impl<I: Lexer> Parser<I> {
/// : declaration_specifiers ';'
/// | declaration_specifiers init_declarator_list ';'
/// ;
/// ```
/// <http://www.quut.com/c/ANSI-C-grammar-y.html#external_declaration>
pub fn external_declaration(&mut self) -> SyntaxResult<Locatable<ExternalDeclaration>> {
let (specifiers, specifier_locations) = self.specifiers()?;

Expand Down Expand Up @@ -169,11 +172,14 @@ impl<I: Lexer> Parser<I> {
}
Ok((specifiers, all_locs))
}
/// ```yacc
/// struct_or_union_specifier
/// : (struct | union) '{' struct_declaration + '}'
/// | (struct | union) identifier '{' struct_declaration + '}'
/// | (struct | union) identifier
/// ;
/// ```
/// <http://www.quut.com/c/ANSI-C-grammar-y.html#struct_or_union_specifier>
fn struct_specifier(
&mut self,
is_struct: bool,
Expand Down Expand Up @@ -217,6 +223,7 @@ impl<I: Lexer> Parser<I> {
Ok(Locatable::new(spec, start))
}

/// ```yacc
/// struct_declaration: (type_specifier | type_qualifier)+ struct_declarator_list ';'
///
/// struct_declarator_list: struct_declarator (',' struct_declarator)* ;
Expand All @@ -226,6 +233,8 @@ impl<I: Lexer> Parser<I> {
/// | ':' constant_expr // bitfield, not supported
/// | declarator ':' constant_expr
/// ;
/// ```
/// <http://www.quut.com/c/ANSI-C-grammar-y.html#struct_declaration>
fn struct_declaration_list(&mut self) -> SyntaxResult<Locatable<ast::StructDeclarationList>> {
//use data::lex::LocationTrait;
let (specifiers, mut spec_location) = self.specifiers()?;
Expand Down Expand Up @@ -272,15 +281,16 @@ impl<I: Lexer> Parser<I> {
location.maybe_merge(spec_location),
))
}
/// ```yacc
/// enum_specifier
/// : 'enum' '{' enumerator_list '}'
/// | 'enum' identifier '{' enumerator_list '}'
/// : 'enum' '{' enumerator_list '}'
/// | 'enum' identifier '{' enumerator_list '}'
// this is not valid for declaring an enum, but it's fine for an enum we've already seen
// e.g. `enum E { A }; enum E e;`

/// | 'enum' identifier
/// ;
/// | 'enum' identifier
/// ;
///
/// enumerator_list
/// : enumerator
Expand All @@ -291,6 +301,8 @@ impl<I: Lexer> Parser<I> {
/// : IDENTIFIER
/// | IDENTIFIER '=' constant_expression
/// ;
/// ```
/// <http://www.quut.com/c/ANSI-C-grammar-y.html#enum_specifier>
// we've already seen an `enum` token,, `location` is where we saw it
fn enum_specifier(
Expand Down Expand Up @@ -414,6 +426,7 @@ impl<I: Lexer> Parser<I> {
* | direct_declarator '(' ')'
* | direct_declarator '(' parameter_type_list ')'
* ;
* <http://www.quut.com/c/ANSI-C-grammar-y.html#direct_declarator>
*
* Additionally, we combine abstract_declarators, because most of the code is the same.
* direct_abstract_declarator
Expand All @@ -427,11 +440,12 @@ impl<I: Lexer> Parser<I> {
* | direct_abstract_declarator '(' ')'
* | direct_abstract_declarator '(' parameter_type_list ')'
* ;
* <http://www.quut.com/c/ANSI-C-grammar-y.html#direct_abstract_declarator>
*
* Because we can't handle left-recursion, we rewrite it as follows:
* direct_abstract_declarator
* | identifier postfix_type*
* : '(' abstract_declarator ')' postfix_type*
* | identifier postfix_type*
* | postfix_type* /* only for abstract_declarators */
* ;
*
Expand All @@ -441,6 +455,7 @@ impl<I: Lexer> Parser<I> {
* | '(' ')'
* | '(' parameter_type_list ')'
* ;
* ```
*
* How do we tell abstract_declarator and parameter_type_list apart?
* parameter_type_list starts with declaration specifiers, abstract_declarator doesn't:
Expand Down Expand Up @@ -588,6 +603,7 @@ impl<I: Lexer> Parser<I> {
* | declaration_specifiers abstract_declarator
* ;
*
* <http://www.quut.com/c/ANSI-C-grammar-y.html#parameter_type_list>
*/
fn parameter_type_list(&mut self) -> SyntaxResult<Locatable<InternalDeclaratorType>> {
let left_paren = self
Expand Down
2 changes: 2 additions & 0 deletions src/parse/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ impl<I: Lexer> Parser<I> {
// : logical_or_expression
// | logical_or_expression '?' expression ':' conditional_expression
// ;
// <http://www.quut.com/c/ANSI-C-grammar-y.html#conditional_expression>
let inner = self.expr()?;
self.expect(Token::Colon)?;
let right_start = self.unary_expr()?;
Expand Down Expand Up @@ -241,6 +242,7 @@ impl<I: Lexer> Parser<I> {
}
// postfix_expression: primary_expression postfix_op*
// primary_expression: '(' expr ')' | 'sizeof' unary_expression | 'alignof' unary_expression | ID | LITERAL
// <http://www.quut.com/c/ANSI-C-grammar-y.html#postfix_expression>
//
// TODO: `sizeof` and `alignof` should be unary expressions, not primary expressions
#[inline]
Expand Down
3 changes: 3 additions & 0 deletions src/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ impl<I: Lexer> Parser<I> {

impl<I: Lexer> Iterator for Parser<I> {
type Item = CompileResult<Locatable<ExternalDeclaration>>;
/// ```yacc
/// translation_unit
/// : external_declaration
/// | translation_unit external_declaration
Expand All @@ -90,6 +91,8 @@ impl<I: Lexer> Iterator for Parser<I> {
/// : declarator compound_statement
/// | declaration_specifiers declarator compound_statement
/// ;
/// ```
/// <http://www.quut.com/c/ANSI-C-grammar-y.html#translation_unit>
fn next(&mut self) -> Option<Self::Item> {
loop {
// check for pending changes from the last declaration
Expand Down
28 changes: 18 additions & 10 deletions src/parse/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ impl<I: Lexer> Parser<I> {
Ok(declaration) => Ok(Stmt::new(StmtType::Decl(declaration), decl.location)),
}
}
/// ```yacc
/// statement
/// : labeled_statement
/// | compound_statement
Expand All @@ -61,13 +62,12 @@ impl<I: Lexer> Parser<I> {
/// | jump_statement
/// ;
///
/// labeled_statement:
/// identifier ':' statement
/// | CASE constant_expr ':' statement
/// | DEFAULT ':' statement
///
/// Result: whether there was an error in the program source
/// Option: empty semicolons still count as a statement (so case labels can work)
/// labeled_statement
/// : identifier ':' statement
/// | CASE constant_expr ':' statement
/// | DEFAULT ':' statement
/// ;
/// ```
pub fn statement(&mut self) -> SyntaxResult<Stmt> {
let _guard = self.recursion_check();
// take out 2 guards since this goes through `compound_statement` before calling itself again
Expand Down Expand Up @@ -242,6 +242,7 @@ impl<I: Lexer> Parser<I> {
})
}
/// do_while_statement: DO statement WHILE '(' expr ')' ';'
/// <http://www.quut.com/c/ANSI-C-grammar-y.html#iteration_statement>
fn do_while_statement(&mut self) -> StmtResult {
let start = self
.expect(Token::Keyword(Keyword::Do))
Expand All @@ -261,7 +262,9 @@ impl<I: Lexer> Parser<I> {
})
}

/// expr_opt: expr ';' | ';'
/// `expr_opt: expr ';' | ';'`
///
/// <http://www.quut.com/c/ANSI-C-grammar-y.html#expression_statement>
///
/// `token` is the delimiter that ends the expression;
/// `token` is usually `;` but sometimes `)` (in `for` loops)
Expand All @@ -275,9 +278,12 @@ impl<I: Lexer> Parser<I> {
}
}

/// ```yacc
/// for_statement:
/// FOR '(' expr_opt ';' expr_opt ';' expr_opt ') statement
/// | FOR '(' declaration expr_opt ';' expr_opt ') statement
/// | FOR '(' declaration expr_opt ';' expr_opt ') statement;
/// ```
/// <http://www.quut.com/c/ANSI-C-grammar-y.html#iteration_statement>
fn for_statement(&mut self) -> StmtResult {
let start = self.expect(Token::Keyword(Keyword::For))?;
let paren = self.expect(Token::LeftParen)?;
Expand Down Expand Up @@ -325,7 +331,9 @@ impl<I: Lexer> Parser<I> {
location: start.location,
})
}
/// goto_statement: GOTO identifier ';'
/// `goto_statement: GOTO identifier ';'`
///
/// <http://www.quut.com/c/ANSI-C-grammar-y.html#jump_statement>
fn goto_statement(&mut self) -> StmtResult {
let start = self.expect(Token::Keyword(Keyword::Goto)).unwrap();
let id = self.expect_id()?;
Expand Down

0 comments on commit a8159c3

Please sign in to comment.