public override void Layout(AstScope currentScope, LayoutContext ctx) { // Is it a data declaration? _dataType = currentScope.FindSymbol(_macroOrDataTypeName) as AstType; if (_dataType != null) { // Work out how many elements in total int totalElements = 0; foreach (var n in _operands) { totalElements += n.EnumData(currentScope).Count(); } // Reserve space ctx.ReserveBytes(_reservedBytes = totalElements * _dataType.SizeOf); return; } // Is it a macro invocation? _macroDefinition = currentScope.FindSymbol(_macroOrDataTypeName + ExprNodeParameterized.MakeSuffix(_operands.Count)) as AstMacroDefinition; if (_macroDefinition != null) { // Create resolved scope _resolvedScope = _macroDefinition.Resolve(currentScope, _operands.ToArray()); // Define macro symbols _macroDefinition.DefineSymbolsResolved(_resolvedScope); // Layout _macroDefinition.LayoutResolved(_resolvedScope, ctx); return; } throw new CodeException($"Unrecognized symbol: '{_macroOrDataTypeName}' is not a known data type or macro (with {_operands.Count} arguments)", SourcePosition); }
AstElement ParseAstElement() { // EOF? if (_tokenizer.Token == Token.EOF) { return(null); } // Blank line? if (_tokenizer.Token == Token.EOL) { return(null); } // ORG Element if (_tokenizer.TrySkipIdentifier("ORG")) { return(new AstOrgElement(ParseExpression())); } // SEEK Element if (_tokenizer.TrySkipIdentifier("SEEK")) { return(new AstSeekElement(ParseExpression())); } // END Element if (_tokenizer.TrySkipIdentifier("END")) { while (_tokenizer.Token != Token.EOF) { _tokenizer.Next(); } return(null); } // Include? if (_tokenizer.TrySkipIdentifier("INCLUDE")) { // Load the include file string includeFile = ParseIncludePath(); // Check for recursive inclusion of the same file if (IsParsing(includeFile)) { throw new CodeException($"error: recursive include file {_tokenizer.TokenRaw}", _tokenizer.TokenPosition); } string includeText; try { includeText = System.IO.File.ReadAllText(includeFile); } catch (Exception x) { throw new CodeException($"error: include file '{_tokenizer.TokenRaw}' - {x.Message}", _tokenizer.TokenPosition); } // Parse it var p = new Parser(); p.OuterParser = this; var content = p.Parse(new StringSource(includeText + "\n", System.IO.Path.GetFileName(includeFile), includeFile)); // Skip the filename _tokenizer.Next(); // Return element return(new AstInclude(includeFile, content)); } // IncBin? if (_tokenizer.TrySkipIdentifier("INCBIN")) { // Load the include file string includeFile = ParseIncludePath(); byte[] includeBytes; try { includeBytes = System.IO.File.ReadAllBytes(includeFile); } catch (Exception x) { throw new CodeException($"error loading incbin file '{includeFile}' - {x.Message}", _tokenizer.TokenPosition); } // Skip the filename _tokenizer.Next(); // Return element return(new AstIncBin(includeFile, includeBytes)); } // DB? /* * if (_tokenizer.TrySkipIdentifier("DB") || _tokenizer.TrySkipIdentifier("DEFB") || _tokenizer.TrySkipIdentifier("DM") || _tokenizer.TrySkipIdentifier("DEFM")) ||{ || var elem = new AstDbElement(); || ParseDxExpressions(elem); || return elem; ||} || ||// DW? ||if (_tokenizer.TrySkipIdentifier("DW") || _tokenizer.TrySkipIdentifier("DEFW")) ||{ || var elem = new AstDwElement(); || ParseDxExpressions(elem); || return elem; ||} */ // DS? if (_tokenizer.TrySkipIdentifier("DS") || _tokenizer.TrySkipIdentifier("DEFS")) { var elem = new AstDsElement(ParseExpression()); if (_tokenizer.TrySkipToken(Token.Comma)) { elem.ValueExpression = ParseExpression(); } return(elem); } // IF Block if (_tokenizer.TrySkipIdentifier("IF")) { return(ParseConditional()); } // PROC? if (_tokenizer.TrySkipIdentifier("PROC")) { _tokenizer.SkipToken(Token.EOL); var proc = new AstProc(); ParseIntoContainer(proc); _tokenizer.SkipIdentifier("ENDP"); return(proc); } // RADIX if (_tokenizer.IsIdentifier("RADIX")) { var saveRadix = _tokenizer.DefaultRadix; try { _tokenizer.DefaultRadix = 10; _tokenizer.Next(); _tokenizer.CheckToken(Token.Number); switch (_tokenizer.TokenNumber) { case 2: case 8: case 10: case 16: break; default: throw new CodeException("Invalid radix - must be 2, 8, 10, or 16", _tokenizer.TokenPosition); } _tokenizer.DefaultRadix = (int)_tokenizer.TokenNumber; _tokenizer.Next(); return(null); } catch { _tokenizer.DefaultRadix = saveRadix; throw; } } // Error if (_tokenizer.TrySkipIdentifier("ERROR")) { _tokenizer.CheckToken(Token.String); var message = _tokenizer.TokenString; _tokenizer.Next(); return(new AstErrorWarning(message, false)); } // Warning if (_tokenizer.TrySkipIdentifier("WARNING")) { _tokenizer.CheckToken(Token.String); var message = _tokenizer.TokenString; _tokenizer.Next(); return(new AstErrorWarning(message, true)); } // DEFBITS? if (_tokenizer.TrySkipIdentifier("DEFBITS")) { // Get the character _tokenizer.CheckToken(Token.String); var character = _tokenizer.TokenString; _tokenizer.Next(); // Skip the comma _tokenizer.SkipToken(Token.Comma); if (_tokenizer.Token == Token.String) { // Get the bit pattern _tokenizer.CheckToken(Token.String); var bitPattern = _tokenizer.TokenString; _tokenizer.Next(); return(new AstDefBits(character, bitPattern)); } else { var bitWidth = ParseExpression(); _tokenizer.SkipToken(Token.Comma); var value = ParseExpression(); return(new AstDefBits(character, value, bitWidth)); } } // BITMAP if (_tokenizer.TrySkipIdentifier("BITMAP")) { // Parse width and height var width = ParseExpression(); _tokenizer.SkipToken(Token.Comma); var height = ParseExpression(); // Bit order spec? bool msbFirst = true; if (_tokenizer.TrySkipToken(Token.Comma)) { if (_tokenizer.TrySkipIdentifier("msb")) { msbFirst = true; } else if (_tokenizer.TrySkipIdentifier("lsb")) { msbFirst = false; } else { throw new CodeException("Expected 'MSB' or 'LSB'", _tokenizer.TokenPosition); } } // Create bitmap ast element var bitmap = new AstBitmap(width, height, msbFirst); // Move to next line _tokenizer.SkipToken(Token.EOL); // Consume all strings, one per line while (_tokenizer.Token == Token.String) { bitmap.AddString(_tokenizer.TokenString); _tokenizer.Next(); _tokenizer.SkipToken(Token.EOL); continue; } // Skip the end dilimeter bitmap.EndPosition = _tokenizer.TokenPosition; _tokenizer.SkipIdentifier("ENDB"); return(bitmap); } if (_tokenizer.Token == Token.Identifier) { // Remember the name var pos = _tokenizer.TokenPosition; var name = _tokenizer.TokenString; _tokenizer.Next(); string[] paramNames = null; // Parameterized EQU? if (_tokenizer.Token == Token.OpenRound && !IsReservedWord(name)) { paramNames = ParseParameterNames(); } // Followed by colon? bool haveColon = false; if (_tokenizer.TrySkipToken(Token.Colon)) { haveColon = true; } // EQU? if (_tokenizer.TrySkipIdentifier("EQU")) { return(new AstEquate(name, ParseOperandExpression(), pos) { ParameterNames = paramNames, }); } // MACRO? if (_tokenizer.TrySkipIdentifier("MACRO")) { _tokenizer.SkipToken(Token.EOL); var macro = new AstMacroDefinition(name, paramNames); ParseIntoContainer(macro); _tokenizer.SkipIdentifier("ENDM"); return(macro); } // STRUCT? if (_tokenizer.TrySkipIdentifier("STRUCT")) { var structDef = new AstStructDefinition(name); // Process field definitions while (_tokenizer.Token != Token.EOF) { // Skip blank lines if (_tokenizer.TrySkipToken(Token.EOL)) { continue; } // End of struct if (_tokenizer.TrySkipIdentifier("ENDS")) { break; } // Capture the field name (or could be type name) var fieldDefPos = _tokenizer.TokenPosition; var fieldName = (string)null; if (!_tokenizer.TrySkipToken(Token.Colon)) { _tokenizer.CheckToken(Token.Identifier); fieldName = _tokenizer.TokenString; // Next token _tokenizer.Next(); } // Must be an identifier (for the type name) _tokenizer.CheckToken(Token.Identifier); var fieldType = _tokenizer.TokenString; _tokenizer.Next(); // Add the field definition structDef.AddField(new AstFieldDefinition(fieldDefPos, fieldName, fieldType, ParseExpressionList())); _tokenizer.SkipToken(Token.EOL); } _tokenizer.SkipToken(Token.EOL); return(structDef); } // Nothing from here on expected parameters if (paramNames != null) { throw new CodeException("Unexpected parameter list in label", pos); } // Was it a label? if (haveColon) { if (IsReservedWord(name)) { throw new CodeException($"Unexpected colon after reserved word '{name}'", pos); } return(new AstLabel(name, pos)); } // Is it an instruction? if (InstructionSet.IsValidInstructionName(name)) { return(ParseInstruction(pos, name)); } // Must be a macro invocation or a data declaration return(ParseMacroInvocationOrDataDeclaration(pos, name)); } // What? throw _tokenizer.Unexpected(); }