Browse Source
Recursive descent parser, although with this simple grammar there won't be any recursion.pull/3/head
Jakob Stoklund Olesen
9 years ago
1 changed files with 201 additions and 1 deletions
@ -1,2 +1,202 @@ |
|||
|
|||
use cretonne; |
|||
// ====--------------------------------------------------------------------------------------====//
|
|||
//
|
|||
// Parser for .cton files.
|
|||
//
|
|||
// ====--------------------------------------------------------------------------------------====//
|
|||
|
|||
use std::result; |
|||
use lexer::{self, Lexer, Token}; |
|||
use cretonne::{types, repr}; |
|||
|
|||
pub use lexer::Location; |
|||
|
|||
/// A parse error is returned when the parse failed.
|
|||
pub struct Error { |
|||
pub location: Location, |
|||
pub message: String, |
|||
} |
|||
|
|||
pub type Result<T> = result::Result<T, Error>; |
|||
|
|||
pub struct Parser<'a> { |
|||
lex: Lexer<'a>, |
|||
|
|||
lex_error: Option<lexer::Error>, |
|||
|
|||
// Current lookahead token.
|
|||
lookahead: Option<Token<'a>>, |
|||
|
|||
// Location of lookahead.
|
|||
location: Location, |
|||
} |
|||
|
|||
impl<'a> Parser<'a> { |
|||
// Consume the current lookahead token and return it.
|
|||
fn consume(&mut self) -> Token<'a> { |
|||
self.lookahead.take().expect("No token to consume") |
|||
} |
|||
|
|||
// Get the current lookahead token, after making sure there is one.
|
|||
fn token(&mut self) -> Option<Token<'a>> { |
|||
if self.lookahead == None { |
|||
match self.lex.next() { |
|||
Some(Ok(lexer::LocatedToken { token, location })) => { |
|||
self.lookahead = Some(token); |
|||
self.location = location; |
|||
} |
|||
Some(Err(lexer::LocatedError { error, location })) => { |
|||
self.lex_error = Some(error); |
|||
self.location = location; |
|||
} |
|||
None => {} |
|||
} |
|||
} |
|||
return self.lookahead; |
|||
} |
|||
|
|||
// Generate an error.
|
|||
fn error(&self, message: &str) -> Error { |
|||
Error { |
|||
location: self.location, |
|||
message: |
|||
// If we have a lexer error latched, report that.
|
|||
match self.lex_error { |
|||
Some(lexer::Error::InvalidChar) => "Invalid character".to_string(), |
|||
None => message.to_string(), |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Match and consume a token without payload.
|
|||
fn match_token(&mut self, want: Token<'a>, err_msg: &str) -> Result<Token<'a>> { |
|||
match self.token() { |
|||
Some(ref t) if *t == want => Ok(self.consume()), |
|||
_ => Err(self.error(err_msg)), |
|||
} |
|||
} |
|||
|
|||
// if the next token is a `want`, consume it, otherwise do nothing.
|
|||
fn optional(&mut self, want: Token<'a>) -> bool { |
|||
match self.token() { |
|||
Some(t) if t == want => { |
|||
self.consume(); |
|||
true |
|||
} |
|||
_ => false, |
|||
} |
|||
} |
|||
|
|||
// Parse a whole function definition.
|
|||
//
|
|||
// function ::= * "function" name signature { ... }
|
|||
//
|
|||
fn parse_function(&mut self) -> Result<repr::Function> { |
|||
try!(self.match_token(Token::Function, "Expected 'function' keyword")); |
|||
|
|||
// function ::= "function" * name signature { ... }
|
|||
let name = try!(self.parse_function_name()); |
|||
|
|||
// function ::= "function" name * signature { ... }
|
|||
let sig = try!(self.parse_signature()); |
|||
|
|||
let mut func = repr::Function::new(); |
|||
|
|||
try!(self.match_token(Token::LBrace, "Expected '{' before function body")); |
|||
try!(self.match_token(Token::RBrace, "Expected '}' after function body")); |
|||
|
|||
Ok(func) |
|||
} |
|||
|
|||
// Parse a function name.
|
|||
//
|
|||
// function ::= "function" * name signature { ... }
|
|||
//
|
|||
fn parse_function_name(&mut self) -> Result<String> { |
|||
match self.token() { |
|||
Some(Token::Identifier(s)) => { |
|||
self.consume(); |
|||
Ok(s.to_string()) |
|||
} |
|||
_ => Err(self.error("Expected function name")), |
|||
} |
|||
} |
|||
|
|||
// Parse a function signature.
|
|||
//
|
|||
// signature ::= * "(" arglist ")" ["->" retlist] [call_conv]
|
|||
// callconv ::= string
|
|||
//
|
|||
// function ::= "function" * name signature { ... }
|
|||
//
|
|||
fn parse_signature(&mut self) -> Result<types::Signature> { |
|||
let mut sig = types::Signature::new(); |
|||
|
|||
try!(self.match_token(Token::LPar, "Expected function signature: '(' args... ')'")); |
|||
// signature ::= "(" * arglist ")" ["->" retlist] [call_conv]
|
|||
sig.argument_types = try!(self.parse_argument_list()); |
|||
try!(self.match_token(Token::RPar, "Expected ')' after function arguments")); |
|||
if self.optional(Token::Arrow) { |
|||
sig.return_types = try!(self.parse_argument_list()); |
|||
if sig.return_types.is_empty() { |
|||
return Err(self.error("Missing return type after '->'")); |
|||
} |
|||
} |
|||
|
|||
// TBD: calling convention.
|
|||
|
|||
Ok(sig) |
|||
} |
|||
|
|||
// Parse (possibly empty) list of function argument / return value types.
|
|||
//
|
|||
// arglist ::= * <empty>
|
|||
// * arg
|
|||
// * arglist "," arg
|
|||
fn parse_argument_list(&mut self) -> Result<Vec<types::ArgumentType>> { |
|||
let mut list = Vec::new(); |
|||
// arglist ::= * <empty>
|
|||
// * arg
|
|||
match self.token() { |
|||
Some(Token::Type(_)) => list.push(try!(self.parse_argument_type())), |
|||
_ => return Ok(list), |
|||
} |
|||
|
|||
// arglist ::= arg *
|
|||
// arglist * "," arg
|
|||
while self.token() == Some(Token::Comma) { |
|||
// arglist ::= arglist * "," arg
|
|||
self.consume(); |
|||
// arglist ::= arglist "," * arg
|
|||
list.push(try!(self.parse_argument_type())); |
|||
} |
|||
|
|||
Ok(list) |
|||
} |
|||
|
|||
// Parse a single argument type with flags.
|
|||
fn parse_argument_type(&mut self) -> Result<types::ArgumentType> { |
|||
// arg ::= * type
|
|||
// * arg flag
|
|||
let mut arg = match self.token() { |
|||
Some(Token::Type(t)) => types::ArgumentType::new(t), |
|||
_ => return Err(self.error("Expected argument type")), |
|||
}; |
|||
loop { |
|||
self.consume(); |
|||
// arg ::= arg * flag
|
|||
match self.token() { |
|||
Some(Token::Identifier(s)) => { |
|||
match s { |
|||
"uext" => arg.extension = types::ArgumentExtension::Uext, |
|||
"sext" => arg.extension = types::ArgumentExtension::Sext, |
|||
"inreg" => arg.inreg = true, |
|||
_ => break, |
|||
} |
|||
} |
|||
_ => break, |
|||
} |
|||
} |
|||
Ok(arg) |
|||
} |
|||
} |
|||
|
Loading…
Reference in new issue