2013-03-11 00:08:38 -05:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inline assembly support.
|
|
|
|
*/
|
|
|
|
|
|
|
|
use core::prelude::*;
|
|
|
|
|
|
|
|
use ast;
|
|
|
|
use codemap::span;
|
|
|
|
use ext::base;
|
|
|
|
use ext::base::*;
|
2013-03-12 02:01:09 -05:00
|
|
|
use parse;
|
|
|
|
use parse::token;
|
|
|
|
|
|
|
|
enum State {
|
|
|
|
Asm,
|
|
|
|
Outputs,
|
|
|
|
Inputs,
|
|
|
|
Clobbers,
|
|
|
|
Options
|
|
|
|
}
|
|
|
|
|
|
|
|
fn next_state(s: State) -> Option<State> {
|
|
|
|
match s {
|
|
|
|
Asm => Some(Outputs),
|
|
|
|
Outputs => Some(Inputs),
|
|
|
|
Inputs => Some(Clobbers),
|
|
|
|
Clobbers => Some(Options),
|
|
|
|
Options => None
|
|
|
|
}
|
|
|
|
}
|
2013-03-11 00:08:38 -05:00
|
|
|
|
|
|
|
pub fn expand_asm(cx: ext_ctxt, sp: span, tts: &[ast::token_tree])
|
|
|
|
-> base::MacResult {
|
2013-03-12 02:01:09 -05:00
|
|
|
|
|
|
|
let p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
|
|
|
|
vec::from_slice(tts));
|
|
|
|
|
|
|
|
let mut asm = ~"";
|
|
|
|
let mut outputs = ~[];
|
|
|
|
let mut inputs = ~[];
|
|
|
|
let mut cons = ~"";
|
|
|
|
let mut volatile = false;
|
2013-03-12 03:02:58 -05:00
|
|
|
let mut alignstack = false;
|
2013-03-12 02:01:09 -05:00
|
|
|
|
|
|
|
let mut state = Asm;
|
|
|
|
loop outer: {
|
|
|
|
match state {
|
|
|
|
Asm => {
|
|
|
|
asm = expr_to_str(cx, p.parse_expr(),
|
|
|
|
~"inline assembly must be a string literal.");
|
|
|
|
}
|
|
|
|
Outputs => {
|
|
|
|
while *p.token != token::EOF &&
|
|
|
|
*p.token != token::COLON &&
|
|
|
|
*p.token != token::MOD_SEP {
|
2013-03-12 02:09:53 -05:00
|
|
|
|
2013-03-12 02:01:09 -05:00
|
|
|
if outputs.len() != 0 {
|
|
|
|
p.eat(&token::COMMA);
|
|
|
|
}
|
2013-03-12 02:09:53 -05:00
|
|
|
|
2013-03-12 02:01:09 -05:00
|
|
|
let constraint = p.parse_str();
|
|
|
|
p.expect(&token::LPAREN);
|
|
|
|
let out = p.parse_expr();
|
|
|
|
p.expect(&token::RPAREN);
|
|
|
|
|
|
|
|
outputs.push((constraint, out));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Inputs => {
|
|
|
|
while *p.token != token::EOF &&
|
|
|
|
*p.token != token::COLON &&
|
|
|
|
*p.token != token::MOD_SEP {
|
2013-03-12 02:09:53 -05:00
|
|
|
|
2013-03-12 02:01:09 -05:00
|
|
|
if inputs.len() != 0 {
|
|
|
|
p.eat(&token::COMMA);
|
|
|
|
}
|
2013-03-12 02:09:53 -05:00
|
|
|
|
2013-03-12 02:01:09 -05:00
|
|
|
let constraint = p.parse_str();
|
|
|
|
p.expect(&token::LPAREN);
|
|
|
|
let in = p.parse_expr();
|
|
|
|
p.expect(&token::RPAREN);
|
|
|
|
|
|
|
|
inputs.push((constraint, in));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Clobbers => {
|
|
|
|
let mut clobs = ~[];
|
|
|
|
while *p.token != token::EOF &&
|
|
|
|
*p.token != token::COLON &&
|
|
|
|
*p.token != token::MOD_SEP {
|
2013-03-12 02:09:53 -05:00
|
|
|
|
2013-03-12 02:01:09 -05:00
|
|
|
if clobs.len() != 0 {
|
|
|
|
p.eat(&token::COMMA);
|
|
|
|
}
|
2013-03-12 02:09:53 -05:00
|
|
|
|
2013-03-12 02:01:09 -05:00
|
|
|
let clob = ~"~{" + *p.parse_str() + ~"}";
|
|
|
|
clobs.push(clob);
|
|
|
|
}
|
|
|
|
|
|
|
|
cons = str::connect(clobs, ",");
|
|
|
|
}
|
|
|
|
Options => {
|
|
|
|
let option = *p.parse_str();
|
2013-03-12 02:09:53 -05:00
|
|
|
|
2013-03-12 02:01:09 -05:00
|
|
|
if option == ~"volatile" {
|
|
|
|
volatile = true;
|
2013-03-12 03:02:58 -05:00
|
|
|
} else if option == ~"alignstack" {
|
|
|
|
alignstack = true;
|
2013-03-12 02:01:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if *p.token == token::COMMA {
|
|
|
|
p.eat(&token::COMMA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while *p.token == token::COLON ||
|
|
|
|
*p.token == token::MOD_SEP ||
|
|
|
|
*p.token == token::EOF {
|
|
|
|
state = if *p.token == token::COLON {
|
|
|
|
p.bump();
|
|
|
|
match next_state(state) {
|
|
|
|
Some(x) => x,
|
|
|
|
None => break outer
|
|
|
|
}
|
|
|
|
} else if *p.token == token::MOD_SEP {
|
|
|
|
p.bump();
|
|
|
|
let s = match next_state(state) {
|
|
|
|
Some(x) => x,
|
|
|
|
None => break outer
|
|
|
|
};
|
|
|
|
match next_state(s) {
|
|
|
|
Some(x) => x,
|
|
|
|
None => break outer
|
|
|
|
}
|
|
|
|
} else if *p.token == token::EOF {
|
|
|
|
break outer;
|
|
|
|
} else {
|
2013-03-12 02:09:53 -05:00
|
|
|
state
|
2013-03-12 02:01:09 -05:00
|
|
|
};
|
|
|
|
}
|
2013-03-11 00:08:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
MRExpr(@ast::expr {
|
|
|
|
id: cx.next_id(),
|
|
|
|
callee_id: cx.next_id(),
|
2013-03-12 03:02:58 -05:00
|
|
|
node: ast::expr_inline_asm(@asm, @cons, volatile, alignstack),
|
2013-03-11 00:08:38 -05:00
|
|
|
span: sp
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2013-03-12 02:01:09 -05:00
|
|
|
|
|
|
|
|
2013-03-11 00:08:38 -05:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|