blob: 42e1a029f175f365187f09fb3b48d43fde2d8089 [file] [log] [blame]
/*=============================================================================
Copyright (c) 2001-2010 Joel de Guzman
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#if !defined(BOOST_SPIRIT_MINI_CC)
#define BOOST_SPIRIT_MINI_CC
#include "mini_c.hpp"
///////////////////////////////////////////////////////////////////////////////
// Our statement grammar and compiler
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
statement<Iterator>::statement(
std::vector<int>& code, symbols<char, function_info>& functions)
: statement::base_type(statement_list)
, code(code)
, functions(functions)
, nvars(0)
, expr(code, vars, functions)
, add_var(var_adder(vars, nvars))
, op(code)
{
namespace phx = boost::phoenix;
identifier %=
raw[lexeme[alpha >> *(alnum | '_')]]
;
var_ref =
lexeme
[
vars [_val = _1]
>> !(alnum | '_') // make sure we have whole words
]
;
var_decl =
lexeme[
"int"
>> !(alnum | '_') // make sure we have whole words
]
> !var_ref // make sure the variable isn't redeclared
> identifier [add_var(_1)]
> (';' | '=' > assignment_rhs(phx::ref(nvars)-1))
;
assignment =
var_ref [_a = _1]
>> '='
> assignment_rhs(_a)
;
assignment_rhs =
expr
> lit(';') [op(op_store, _r1)]
;
if_statement =
lit("if")
>> '('
> expr [
op(op_jump_if, 0), // we shall fill this (0) in later
_a = size(phx::ref(code))-1 // mark its position
]
> ')'
> statement_ [
// now we know where to jump to (after the if branch)
phx::ref(code)[_a] = size(phx::ref(code))
]
>>
-(
lexeme[
"else"
>> !(alnum | '_') // make sure we have whole words
] [
phx::ref(code)[_a] += 2, // adjust for the "else" jump
op(op_jump, 0), // we shall fill this (0) in later
_a = size(phx::ref(code))-1 // mark its position
]
> statement_ [
// now we know where to jump to (after the else branch)
phx::ref(code)[_a] = size(phx::ref(code))
]
)
;
while_statement =
lit("while") [
_a = size(phx::ref(code)) // mark our position
]
>> '('
> expr [
op(op_jump_if, 0), // we shall fill this (0) in later
_b = size(phx::ref(code))-1 // mark its position
]
> ')'
> statement_ [
op(op_jump, _a), // loop back
// now we know where to jump to (to exit the loop)
phx::ref(code)[_b] = size(phx::ref(code))
]
;
compound_statement =
'{' >> -statement_list >> '}'
;
return_statement =
lexeme[
"return"
>> !(alnum | '_') // make sure we have whole words
]
>> -(
eps(phx::ref(has_return)) > expr [op(op_return)]
)
> ';'
;
statement_ =
var_decl
| assignment
| compound_statement
| if_statement
| while_statement
| return_statement
;
statement_list = +statement_;
identifier.name("identifier");
var_ref.name("variable-reference");
var_decl.name("variable-declaration");
assignment.name("assignment");
assignment_rhs.name("assignment-rhs");
if_statement.name("if-statement");
while_statement.name("while-statement");
compound_statement.name("compound-statement");
return_statement.name("return-statement");
statement_.name("statement");
statement_list.name("statement-list");
on_error<fail>(statement_list, ::error_handler(_4, _3, _2));
}
#endif