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 fd48621 commit e7dedb2
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 103 deletions.
261 changes: 158 additions & 103 deletions src/asm/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1331,141 +1331,196 @@ 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();
let mut size_guess = 0;

// 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 line = 0;

let mut subs_tokens: Vec<syntax::Token> = Vec::new();
while !subs_parser.is_over()
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()
{
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();
line += 1;

let token_sub = match info.args.get_token_sub(&arg_name)
// 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 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

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)
{
subs_tokens.push(subs_parser.advance());
let label_tk = subparser.expect(syntax::TokenKind::Identifier)?;
let label_name = label_tk.excerpt.as_ref().unwrap();
//println!("Label: {} / {} / {}", line, found_labels, label_name);
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 mut subparser = syntax::Parser::new(Some(info.report.clone()), &subs_tokens);
subparser.suppress_reports();
dbg!(matches.size_guess);

//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())?;
if found_labels == 0
{
let value = self.resolve_rule_invocation(
info.report.clone(),
&matches,
fileserver,
false,
info.args).unwrap_or(expr::Value::make_integer(0));

if value.get_bigint().is_some() && value.get_bigint().unwrap().size.is_some() {
let size = value.get_bigint().unwrap().size.unwrap();
//println!("Size guess: {} / {} / {}", line, found_labels, size);
if size_guess == 0
{
size_guess = size;
}
inner_ctx.bit_offset += size;
}

}

let value = self.resolve_rule_invocation(
info.report.clone(),
&matches,
fileserver,
true,
info.args)?;

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

let (bigint, size) = match value.get_bigint()
{
Some(bigint) =>
{
match bigint.size
if found_labels == 1
{
let value = self.resolve_rule_invocation(
info.report.clone(),
&matches,
fileserver,
true,
info.args)?;

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

let (bigint, size) = match value.get_bigint()
{
Some(size) => (bigint, size),
None =>
Some(bigint) =>
{
match bigint.size
{
Some(size) => (bigint, size),
None =>
{
info.report.error_span(
"cannot infer size of instruction",
&subparser_span);

return Err(());
}
}
}

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

return Err(());
}
};

if size > 0
{

//println!("Size: {} / {} / {} / {}", line, found_labels, size, size_guess);
if size_guess == 0
{
size_guess = size;
}

if size != size_guess
{

info.report.error_span(
"Size did not converge.",
&subparser_span);

return Err(());
}
}
}

_ =>
{
info.report.error_span(
"wrong type returned from instruction",
&subparser_span);
if result.size.unwrap() == 0
{
result = bigint;
}
else
{
result = result.concat(
(result.size.unwrap(), 0),
&bigint,
(size, 0));
}

return Err(());
inner_ctx.bit_offset += size;
}
}
};

if size > 0
{
if result.size.unwrap() == 0
{
result = bigint;
}
else
{
result = result.concat(
(result.size.unwrap(), 0),
&bigint,
(size, 0));
}

inner_ctx.bit_offset += size;

//println!(" value = {:?}", value);
}
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 e7dedb2

Please sign in to comment.