The Parser now uses the Lexer Tokens.

The parser can now handle code block start and end, and it can process
the include file useing the Lexer Tokens. Previously it was trying to do
this by reading lines.
This commit is contained in:
Myrddin Dundragon 2016-07-27 01:49:05 -04:00
parent 282926f07c
commit 0ee91d15c9
2 changed files with 189 additions and 87 deletions

View File

@ -3,6 +3,8 @@ use std::io::Write;
use std::path::Path; use std::path::Path;
use ::lexer::Lexer; use ::lexer::Lexer;
use ::lexer::Token;
use ::lexer::TokenTypes;
use ::parser::Parser; use ::parser::Parser;
use ::reader::Reader; use ::reader::Reader;
use ::util::Util; use ::util::Util;
@ -29,6 +31,7 @@ pub fn read_file(util: &Util, input_path: &Path) -> String
{ {
let mut output: String; let mut output: String;
let mut reader: Reader; let mut reader: Reader;
let mut parser: Parser;
let mut lines: Vec<String>; let mut lines: Vec<String>;
// Create the output string of the compiled file. // Create the output string of the compiled file.
@ -37,18 +40,28 @@ pub fn read_file(util: &Util, input_path: &Path) -> String
// Create a Reader from the given input file. // Create a Reader from the given input file.
reader = Reader::from_file(input_path); reader = Reader::from_file(input_path);
Lexer::scan(&mut reader); //
match Lexer::scan(&mut reader)
/* {
Ok(tokens) =>
{
// Parse the file and turn it into a set of compiled lines. // Parse the file and turn it into a set of compiled lines.
lines = Parser::parse(&util, &mut reader); parser = Parser::new(util);
lines = parser.parse(tokens);
// Add all these lines to the final output. // Add all these lines to the final output.
for line in lines.into_iter() for line in lines.into_iter()
{ {
output.push_str(&line); output.push_str(&line);
} }
*/ }
Err(error) =>
{
error!("{}", error);
}
}
// Return the final output. // Return the final output.
output output
} }

View File

@ -1,77 +1,158 @@
use std::path::PathBuf; use std::path::PathBuf;
use ::compiler::read_file; use ::compiler::read_file;
use ::lexer::Token;
use ::lexer::TokenTypes;
use ::reader::Reader; use ::reader::Reader;
use ::util::Util; use ::util::Util;
/// ///
pub enum Parser pub struct Parser<'a>
{ {
///
util: &'a Util
} }
/// ///
fn process_line(util: &Util, output: &mut Vec<String>, line: String) fn flush_buffer(output: &mut Vec<String>, buffer: &mut String)
{ {
let start: usize; // Put the buffer into the output list.
let end: usize; output.push(buffer.clone());
// Clear the buffer out.
buffer.clear();
}
///
fn buffer_token(buffer: &mut String, token: &Token)
{
buffer.push_str(&token.to_string());
}
///
fn is_start_of_code_section(tokens: &Vec<Token>, pos: &usize) -> bool
{
// Check if this is the start of a code section.
if *pos + 1usize < tokens.len() &&
tokens[*pos].get_type() == TokenTypes::Symbol &&
tokens[*pos + 1usize].get_type() == TokenTypes::Symbol &&
tokens[*pos].to_string() == "{" &&
tokens[*pos + 1usize].to_string() == "@"
{
return true;
}
false
}
///
fn is_end_of_code_section(tokens: &Vec<Token>, pos: &usize) -> bool
{
// Check if this is the start of a code section.
if *pos + 1usize < tokens.len() &&
tokens[*pos].get_type() == TokenTypes::Symbol &&
tokens[*pos + 1usize].get_type() == TokenTypes::Symbol &&
tokens[*pos].to_string() == "@" &&
tokens[*pos + 1usize].to_string() == "}"
{
return true;
}
false
}
///
fn is_include_statement(tokens: &Vec<Token>, pos: &usize) -> bool
{
// Check if this is an include statement.
if *pos + 4usize < tokens.len() &&
tokens[*pos + 0usize].get_type() == TokenTypes::Keyword &&
tokens[*pos + 1usize].get_type() == TokenTypes::Symbol &&
tokens[*pos + 2usize].get_type() == TokenTypes::StaticString &&
tokens[*pos + 3usize].get_type() == TokenTypes::Symbol &&
tokens[*pos + 4usize].get_type() == TokenTypes::Symbol &&
tokens[*pos + 0usize].to_string() == "include" &&
tokens[*pos + 1usize].to_string() == "(" &&
tokens[*pos + 3usize].to_string() == ")" &&
tokens[*pos + 4usize].to_string() == ";"
{
return true;
}
false
}
impl<'a> Parser<'a>
{
///
pub fn new(util_ptr: &'a Util) -> Parser
{
Parser
{
util: util_ptr
}
}
///
pub fn parse(&mut self, tokens: Vec<Token>) -> Vec<String>
{
let mut is_in_code_block: bool;
let mut position: usize;
let mut include_file: PathBuf; let mut include_file: PathBuf;
let mut processed_line: String; let mut buffer: String;
let mut output: Vec<String>;
// Copy the given line. // Create a new set of lines to hold the parsed data.
processed_line = line.clone(); output = Vec::new();
// Remove any code block brackets. // Setup the String buffer.
processed_line = processed_line.replace("{@", ""); buffer = String::new();
processed_line = processed_line.replace("@}", "");
// Just handling the include code right now. // Parse the tokens passed in.
if processed_line.contains("include") == true is_in_code_block = false;
position = 0usize;
while position < tokens.len()
{ {
// Parse one or more include statements on a line. if is_in_code_block == true
{
if is_end_of_code_section(&tokens, &position) == true
{
// Flush any previous buffer.
flush_buffer(&mut output, &mut buffer);
// Cut out the include statement so it can be processed. // Mark that we are no longer in a code block.
match processed_line.find("\"") is_in_code_block = false;
{
Some(location) => // Two tokens have been read.
{ position += 2;
// Add one to move past the quote mark.
start = location + 1usize; println!("{}: Is end of code block.", position);
} }
else if is_include_statement(&tokens, &position) == true
None =>
{ {
start = 0usize; // Flush any previous buffer.
} flush_buffer(&mut output, &mut buffer);
}
match processed_line[start..].find("\"") // Convert the String portion to a PathBuf.
{ include_file =
Some(location) => PathBuf::from(
{ tokens[position + 2usize].to_string().replace("\"", ""));
end = start + location;
}
None =>
{
end = start + 0usize;
}
}
include_file = PathBuf::from(&processed_line[start..end]);
// Try to find the include file in one of the // Try to find the include file in one of the
// include directories. // include directories.
match util.get_include_file_path(&include_file) match self.util.get_include_file_path(&include_file)
{ {
Some(file) => Some(file) =>
{ {
// Process the include file found and add it to // Process the include file found and add it to
// the output list. // the output list.
output.push(read_file(util, &file)); output.push(read_file(self.util, &file));
} }
None => None =>
@ -80,42 +161,50 @@ fn process_line(util: &Util, output: &mut Vec<String>, line: String)
include_file); include_file);
} }
} }
// Five tokens have been read.
position += 5;
println!("{}: Is include statement.", position);
} }
else else
{ {
output.push(processed_line); // This token is nothing interesting, so
// process it generally and move the position forward.
buffer_token(&mut buffer, &tokens[position]);
position += 1;
} }
}
impl Parser
{
///
pub fn parse(util: &Util, reader: &mut Reader) -> Vec<String>
{
let mut output: Vec<String>;
// Create a new set of lines to hold the parsed data.
output = Vec::new();
// Start parsing all the given lines.
while reader.is_eob() == false
{
match reader.consume_line()
{
Ok(line) =>
{
process_line(util, &mut output, line)
} }
else
Err(error) =>
{ {
error!("{}", error); if is_start_of_code_section(&tokens, &position) == true
{
// Flush any previous buffer.
flush_buffer(&mut output, &mut buffer);
// Mark that we are in a code block.
is_in_code_block = true;
// Two tokens have been read.
position += 2;
println!("{}: Is start of code block.", position);
}
else
{
// This token is nothing interesting, so
// process it generally and move the position forward.
buffer_token(&mut buffer, &tokens[position]);
position += 1;
} }
} }
} }
// Flush any left over buffer.
flush_buffer(&mut output, &mut buffer);
// Return the parsed input. // Return the parsed input.
output output
} }