public AsmContext Assemble(string content, string fileName = null) { var symbols = new AsmSymbols(); IList<Token> tokens = new List<Token>(); LoadRecursive(content, tokens, fileName); tokens = ProcessSymbolConstants(tokens, symbols); AsmContext last = null; for (var i = 1; i < 10; i++) { var context = new AsmContext { Queue = new TokensQueue(tokens), Symbols = symbols, Pass = i }; var parser = new AsmParser(context); AssemblePass(context, parser); if (TheSame(last, context)) break; last = context; } return last; }
private static void ProcessReserveWords(AsmParser parser, AsmSection output) { var cnt = parser.CalculateExpression(); output.ReserveBytes((int)cnt * 2); }
private static void ProcessOrg(AsmParser parser, AsmSection output) { var val = parser.CalculateExpression(); output.Offset = (int)val; }
private static void ProcessDataWords(AsmParser parser, AsmSection output) { do { if (parser.IsEndOfLine) { throw new TokenException("expected data words", parser.LastReadToken); } var token = parser.PeekToken(); if (token.Type == TokenType.String) { token = parser.ReadToken(TokenType.String); foreach (var ch in token.StringValue) { output.EmitWord(ch); } } else { var val = parser.ReadUshort(); output.EmitWord(val); } if (parser.IsEndOfLine) break; var commaPreview = parser.PeekToken(); if (commaPreview.Type != TokenType.Comma) break; parser.ReadToken(TokenType.Comma); } while (true); }
private static void ProcessDataDirective(Token token, AsmParser parser, AsmSection output) { switch (token.StringValue.ToLower()) { case "db": ProcessDataBytes(parser, output); break; case "dw": ProcessDataWords(parser, output); break; case "rb": ProcessReserveBytes(parser, output); break; case "rw": ProcessReserveWords(parser, output); break; default: throw new TokenException("invalid directive " + token.StringValue, token); } }
private static void ProcessDataBytes(AsmParser parser, AsmSection output) { do { if (parser.IsEndOfLine) { throw new TokenException("expected data bytes", parser.LastReadToken); } var token = parser.PeekToken(); if (token.Type == TokenType.String) { token = parser.ReadToken(TokenType.String); foreach (var ch in token.StringValue) { if (ch > 255) { throw new TokenException("unicode character cannot be translated to byte", token); } output.EmitByte((byte)ch); } } else { var val = parser.ReadByte(); output.EmitByte(val); } if (parser.IsEndOfLine) break; var commaPreview = parser.PeekToken(); if (commaPreview.Type != TokenType.Comma) break; parser.ReadToken(TokenType.Comma); } while (true); }
private static bool CheckData(Token token, AsmContext context, AsmParser parser) { if (IsDataDirective(token)) { ProcessDataDirective(token, parser, context.CurrentSection); return true; } if (!context.Queue.IsEndOfLine) { var preview = context.Queue.Peek(); if (IsDataDirective(preview)) { context.Queue.Read(TokenType.Literal); context.DefineLabel(token); ProcessDataDirective(preview, parser, context.CurrentSection); return true; } } return false; }
private static void AssemblePass(AsmContext context, AsmParser parser) { while (context.Queue.Count > 0) { SkipEmptyLines(context); if (context.Queue.Count == 0) break; AssembleLine(context, parser); } }
private static void AssembleLine(AsmContext context, AsmParser parser) { var token = context.Queue.Read(TokenType.Literal); try { if (CheckLabel(token, context)) { return; } if (CheckData(token, context, parser)) { return; } switch (token.StringValue.ToLower()) { case "section": ProcessSection(context); break; case "org": ProcessOrg(parser, context.CurrentSection); break; default: var opcode = AvrOpcodes.Get(token.StringValue); if (opcode != null) { opcode.Compile(parser, context.CurrentSection); } else { throw new TokenException("Illegal instruction " + token.StringValue, token); } break; } if (context.Queue.Count > 0) { var nl = context.Queue.Peek(); if (nl.Type != TokenType.NewLine) { throw new TokenException("Extra characters on line", nl); } } } catch (PureSectionDataException exc) { throw new PureSectionDataException(exc.Message, token); } }