public static bool IsReservedWord(string str) { if (str == null) { return(false); } if (InstructionSet.IsConditionFlag(str) || InstructionSet.IsValidInstructionName(str) || InstructionSet.IsValidRegister(str)) { return(true); } switch (str.ToUpperInvariant()) { case "ORG": case "SEEK": case "END": case "INCLUDE": case "INCBIN": case "EQU": case "DB": case "DEFB": case "DEFM": case "DW": case "DEFW": case "DS": case "DEFS": case "IF": case "ENDIF": case "ELSE": case "ELSEIF": case "PROC": case "ENDP": case "MACRO": case "ENDM": case "DEFBITS": case "BITMAP": case "ENDB": case "ERROR": case "WARNING": case "RADIX": case "STRUCT": case "ENDS": case "BYTE": case "WORD": return(true); } return(false); }
ExprNode ParseLeaf() { var pos = _tokenizer.TokenPosition; // Number literal? if (_tokenizer.Token == Token.Number) { var node = new ExprNodeNumberLiteral(pos, _tokenizer.TokenNumber); _tokenizer.Next(); return(node); } // String literal? if (_tokenizer.Token == Token.String) { var str = _tokenizer.TokenString; _tokenizer.Next(); return(new ExprNodeStringLiteral(pos, str)); } // Defined operator? if (_tokenizer.TrySkipIdentifier("defined")) { _tokenizer.SkipToken(Token.OpenRound); _tokenizer.CheckToken(Token.Identifier); var node = new ExprNodeIsDefined(pos, _tokenizer.TokenString); _tokenizer.Next(); _tokenizer.SkipToken(Token.CloseRound); return(node); } // Sizeof operator? if (_tokenizer.TrySkipIdentifier("sizeof")) { _tokenizer.SkipToken(Token.OpenRound); var node = new ExprNodeSizeOf(pos, ParseExpression()); _tokenizer.SkipToken(Token.CloseRound); return(node); } // Identifier if (_tokenizer.Token == Token.Identifier) { // Special identifier if (InstructionSet.IsConditionFlag(_tokenizer.TokenString) || InstructionSet.IsValidRegister(_tokenizer.TokenString)) { var node = new ExprNodeRegisterOrFlag(pos, _tokenizer.TokenString); _tokenizer.Next(); return(node); } else { var node = new ExprNodeIdentifier(pos, _tokenizer.TokenString); _tokenizer.Next(); if (_tokenizer.Token == Token.Period) { ExprNode retNode = node; while (_tokenizer.TrySkipToken(Token.Period)) { _tokenizer.CheckToken(Token.Identifier); retNode = new ExprNodeMember(_tokenizer.TokenPosition, _tokenizer.TokenString, retNode); _tokenizer.Next(); } return(retNode); } if (_tokenizer.Token == Token.OpenRound) { node.Arguments = ParseArgumentList(); } return(node); } } // Parens? if (_tokenizer.TrySkipToken(Token.OpenRound)) { var node = ParseExpressionList(); _tokenizer.SkipToken(Token.CloseRound); return(node); } // Array? if (_tokenizer.Token == Token.OpenSquare) { return(ParseOrderedStructData()); } // Map? if (_tokenizer.Token == Token.OpenBrace) { return(ParseNamedStructData()); } throw new CodeException($"syntax error in expression: {Tokenizer.DescribeToken(_tokenizer.Token, _tokenizer.TokenRaw)}", _tokenizer.TokenPosition); }
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(); }
public override void Layout(AstScope currentScope, LayoutContext ctx) { var sb = new StringBuilder(); sb.Append(_mnemonic); for (int i = 0; i < _operands.Count; i++) { if (i > 0) { sb.Append(","); } else { sb.Append(" "); } var o = _operands[i]; var addressingMode = o.GetAddressingMode(currentScope); if ((addressingMode & AddressingMode.SubOp) != 0) { sb.Append(o.GetSubOp()); sb.Append(" "); addressingMode = addressingMode & ~AddressingMode.SubOp; } switch (addressingMode) { case AddressingMode.Deref | AddressingMode.Immediate: sb.Append($"(?)"); break; case AddressingMode.Deref | AddressingMode.Register: { var reg = o.GetRegister(currentScope); if (IsIndexRegister(reg)) { sb.Append($"({reg}+?)"); } else { sb.Append($"({reg})"); } } break; case AddressingMode.Deref | AddressingMode.RegisterPlusImmediate: sb.Append($"({o.GetRegister(currentScope)}+?)"); break; case AddressingMode.Immediate: sb.Append($"?"); break; case AddressingMode.Register: sb.Append($"{o.GetRegister(currentScope)}"); break; case AddressingMode.RegisterPlusImmediate: sb.Append($"{o.GetRegister(currentScope)}+?"); break; default: sb.Append($"<illegal expression>"); break; } } _instruction = InstructionSet.Find(sb.ToString()); if (_instruction == null) { Log.Error(_position, $"invalid addressing mode: {sb.ToString()}"); } else { ctx.ReserveBytes(_instruction.Length); } }
public bool ProcessArg(string arg) { if (arg == null) { return(true); } if (arg.StartsWith("#")) { return(true); } // Response file if (arg.StartsWith("@")) { // Get the fully qualified response file name string strResponseFile = System.IO.Path.GetFullPath(arg.Substring(1)); // Load and parse the response file var args = Utils.ParseCommandLine(System.IO.File.ReadAllText(strResponseFile)); // Set the current directory string OldCurrentDir = System.IO.Directory.GetCurrentDirectory(); System.IO.Directory.SetCurrentDirectory(System.IO.Path.GetDirectoryName(strResponseFile)); // Load the file bool bRetv = ProcessArgs(args); // Restore current directory System.IO.Directory.SetCurrentDirectory(OldCurrentDir); return(bRetv); } // Args are in format [/-]<switchname>[:<value>]; if (arg.StartsWith("/") || arg.StartsWith("-")) { string SwitchName = arg.Substring(arg.StartsWith("--") ? 2 : 1); string Value = null; int colonpos = SwitchName.IndexOf(':'); if (colonpos >= 0) { // Split it Value = SwitchName.Substring(colonpos + 1); SwitchName = SwitchName.Substring(0, colonpos); } switch (SwitchName) { case "help": case "h": case "?": ShowLogo(); ShowHelp(); return(false); case "v": ShowLogo(); return(false); case "instructionSet": InstructionSet.DumpAll(); return(false); case "ast": if (Value != null) { _astFile = Value; } else { _astFile = ":default"; } break; case "sym": if (Value != null) { _symbolsFile = Value; } else { _symbolsFile = ":default"; } break; case "lst": case "list": if (Value != null) { _listFile = Value; } else { _listFile = ":default"; } break; case "define": if (Value == null) { throw new InvalidOperationException("--define: requires argument value"); } else { var eqPos = Value.IndexOf('='); if (eqPos < 0) { _userDefines.Add(Value, null); } else { _userDefines.Add(Value.Substring(0, eqPos), Value.Substring(eqPos + 1)); } } break; case "output": if (Value == null) { throw new InvalidOperationException("--output: requires argument value"); } else { _outputFile = Value; } break; case "include": if (Value == null) { throw new InvalidOperationException("--include: requires argument value"); } else { try { _includePaths.Add(System.IO.Path.GetFullPath(Value)); } catch (Exception x) { throw new InvalidOperationException($"Invalid include path: {Value} - {x.Message}"); } } break; default: throw new InvalidOperationException(string.Format("Unknown switch '{0}'", arg)); } } else { if (_inputFile == null) { _inputFile = arg; } else { throw new InvalidOperationException(string.Format("Too many command line arguments, don't know what to do with '{0}'", arg)); } } return(true); }