From b468c49402dcc17c51a79c1b28b52b22cba42fd8 Mon Sep 17 00:00:00 2001 From: Emmett Brown Date: Tue, 19 Oct 2021 23:41:05 +0200 Subject: [PATCH] Final fix for issue #115: local labels in asm{} are resolved out-of-order --- src/asm/state.rs | 230 +++++++++++++++++++++++-------------------- tests/issue115/4.asm | 26 +++++ 2 files changed, 151 insertions(+), 105 deletions(-) create mode 100644 tests/issue115/4.asm diff --git a/src/asm/state.rs b/src/asm/state.rs index 6b079220..bdfe428d 100644 --- a/src/asm/state.rs +++ b/src/asm/state.rs @@ -1331,141 +1331,161 @@ impl State fileserver: &dyn util::FileServer) -> Result { - // 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 = 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 = 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)) } diff --git a/tests/issue115/4.asm b/tests/issue115/4.asm new file mode 100644 index 00000000..b229fd15 --- /dev/null +++ b/tests/issue115/4.asm @@ -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 \ No newline at end of file