Skip to content
This repository has been archived by the owner on Dec 10, 2023. It is now read-only.

Commit

Permalink
Final fix for issue hlorenzi#115: local labels in asm{} are resolved …
Browse files Browse the repository at this point in the history
…out-of-order
  • Loading branch information
Emmett81 committed Oct 21, 2021
1 parent 7b43243 commit b468c49
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 105 deletions.
230 changes: 125 additions & 105 deletions src/asm/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1331,141 +1331,161 @@ impl State
fileserver: &dyn util::FileServer)
-> Result<expr::Value, ()>
{
// Clone the context in order to advance the logical address
// between instructions.
let mut inner_ctx = ctx.clone();

let mut result = util::BigInt::new(0, Some(0));

let mut parser = syntax::Parser::new(Some(info.report.clone()), info.tokens);

//println!("asm block `{}`", fileserver.get_excerpt(&parser.get_full_span()));

while !parser.is_over()
{
// Substitute `{x}` occurrences with tokens from the argument
let mut subs_parser = parser.slice_until_linebreak_over_nested_braces();
let subparser_span = subs_parser.get_full_span();
// Parse the tokens twice, once to find the labels
// and then to assemble the output
for found_labels in 0..2 {

// Clone the context in order to advance the logical address
// between instructions.
let mut inner_ctx = ctx.clone();

//println!("> instr `{}`", fileserver.get_excerpt(&subparser_span));
let mut parser = syntax::Parser::new(Some(info.report.clone()), info.tokens);

let mut subs_tokens: Vec<syntax::Token> = Vec::new();
while !subs_parser.is_over()
//println!("asm block `{}`", fileserver.get_excerpt(&parser.get_full_span()));

while !parser.is_over()
{
if let Some(open_token) = subs_parser.maybe_expect(syntax::TokenKind::BraceOpen)
{
let arg_name_token = subs_parser.expect(syntax::TokenKind::Identifier)?;
let arg_name = arg_name_token.excerpt.as_ref().unwrap();
// Substitute `{x}` occurrences with tokens from the argument
let mut subs_parser = parser.slice_until_linebreak_over_nested_braces();
let subparser_span = subs_parser.get_full_span();

//println!("> instr `{}`", fileserver.get_excerpt(&subparser_span));

let token_sub = match info.args.get_token_sub(&arg_name)
let mut subs_tokens: Vec<syntax::Token> = Vec::new();
while !subs_parser.is_over()
{
if let Some(open_token) = subs_parser.maybe_expect(syntax::TokenKind::BraceOpen)
{
None =>
let arg_name_token = subs_parser.expect(syntax::TokenKind::Identifier)?;
let arg_name = arg_name_token.excerpt.as_ref().unwrap();

let token_sub = match info.args.get_token_sub(&arg_name)
{
info.report.error_span("unknown argument", &arg_name_token.span);
return Err(());
}
Some(t) => t
};
None =>
{
info.report.error_span("unknown argument", &arg_name_token.span);
return Err(());
}
Some(t) => t
};

let close_token = subs_parser.expect(syntax::TokenKind::BraceClose)?;
let sub_span = open_token.span.join(&close_token.span);
let close_token = subs_parser.expect(syntax::TokenKind::BraceClose)?;
let sub_span = open_token.span.join(&close_token.span);

for token in token_sub
for token in token_sub
{
let mut sub_token = token.clone();
sub_token.span = sub_span.clone();
subs_tokens.push(sub_token);
}
}
else
{
let mut sub_token = token.clone();
sub_token.span = sub_span.clone();
subs_tokens.push(sub_token);
subs_tokens.push(subs_parser.advance());
}
}
else
{
subs_tokens.push(subs_parser.advance());
}
}

let mut subparser = syntax::Parser::new(Some(info.report.clone()), &subs_tokens);
subparser.suppress_reports();
let mut subparser = syntax::Parser::new(Some(info.report.clone()), &subs_tokens);
subparser.suppress_reports();

//println!("> after subs `{:?}`", subs_tokens);

if subparser.next_is(0, syntax::TokenKind::Identifier) &&
subparser.next_is(1, syntax::TokenKind::Colon)
{
let label_tk = subparser.expect(syntax::TokenKind::Identifier)?;
let label_name = label_tk.excerpt.as_ref().unwrap();
info.args.set_local(
label_name,
expr::Value::make_integer(
self.get_addr(info.report.clone(), &inner_ctx, &subparser_span)?)
);
subparser.expect(syntax::TokenKind::Colon)?;
}
else
{
let matches = asm::parser::match_rule_invocation(
&self,
subparser,
inner_ctx.clone(),
fileserver,
info.report.clone())?;

let value = self.resolve_rule_invocation(
info.report.clone(),
&matches,
fileserver,
true,
info.args)?;
//println!("> after subs `{:?}`", subs_tokens);

//println!(" value = {:?}", value);

let (bigint, size) = match value.get_bigint()
if subparser.next_is(0, syntax::TokenKind::Identifier) &&
subparser.next_is(1, syntax::TokenKind::Colon)
{
Some(bigint) =>
{
match bigint.size
let label_tk = subparser.expect(syntax::TokenKind::Identifier)?;
let label_name = label_tk.excerpt.as_ref().unwrap();
info.args.set_local(
label_name,
expr::Value::make_integer(
self.get_addr(info.report.clone(), &inner_ctx, &subparser_span)?));
subparser.expect(syntax::TokenKind::Colon)?;
}
else
{
let matches = asm::parser::match_rule_invocation(
&self,
subparser,
inner_ctx.clone(),
fileserver,
info.report.clone())?;

let value: expr::Value;
if found_labels == 0
{
Some(size) => (bigint, size),
None =>
// Ignore errors while parsing for labels
value = self.resolve_rule_invocation(
info.report.clone(),
&matches,
fileserver,
false,
info.args).unwrap_or(expr::Value::make_integer(0));
}
else
{
value = self.resolve_rule_invocation(
info.report.clone(),
&matches,
fileserver,
true,
info.args)?;
}

//println!(" value = {:?}", value);

if value.get_bigint().is_some() {
let bigint = value.get_bigint().unwrap();

if bigint.size.is_some()
{
let size = bigint.size.unwrap();

if size > 0
{
// Assemble output in final pass
if found_labels == 1
{
if result.size.unwrap() == 0
{
result = bigint;
}
else
{
result = result.concat(
(result.size.unwrap(), 0),
&bigint,
(size, 0));
}
}
inner_ctx.bit_offset += size;
}
} else {
// Throw error on final pass
if found_labels == 1
{
info.report.error_span(
"cannot infer size of instruction",
&subparser_span);

return Err(());
}
}
}

_ =>
{
info.report.error_span(
"wrong type returned from instruction",
&subparser_span);

return Err(());
}
};

if size > 0
{
if result.size.unwrap() == 0
{
result = bigint;
}
else
{
result = result.concat(
(result.size.unwrap(), 0),
&bigint,
(size, 0));
} else {
// Throw error on final pass
if found_labels == 1
{
info.report.error_span(
"wrong type returned from instruction",
&subparser_span);
return Err(());
}
}

inner_ctx.bit_offset += size;
}
parser.expect_linebreak()?;
}
parser.expect_linebreak()?;
}

//println!(" result size = {:?}", result.size);
Ok(expr::Value::make_integer(result))
}
Expand Down
26 changes: 26 additions & 0 deletions tests/issue115/4.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ruledef {
emit {x:u8} => x

test => asm
{
test2 end
test2 end
end:
}

test2 {l: u32} => asm
{
emit l
emit end
end:
}

run => asm
{
test
emit 0x10
}
}

run ; = 0x04_02_04_04_10
emit $ ; = 0x05

0 comments on commit b468c49

Please sign in to comment.