Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Aug 21st, 2012  |  syntax: None  |  size: 24.29 KB  |  hits: 19  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. /*
  2. Copyright (c) 2012, Alexander Wood (unsafeIO)
  3. All rights reserved.
  4.  
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7.  
  8. 1. Redistributions of source code must retain the above copyright notice, this
  9.    list of conditions and the following disclaimer.
  10. 2. Redistributions in binary form must reproduce the above copyright notice,
  11.    this list of conditions and the following disclaimer in the documentation
  12.    and/or other materials provided with the distribution.
  13.  
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  18. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25.  
  26. using System;
  27. using System.Collections.Generic;
  28. using System.Linq;
  29. using System.Globalization;
  30. using System.IO;
  31.  
  32. namespace Assembler
  33. {
  34.     public enum TokenType
  35.     {
  36.         Word, Number, Comma, Label, Plus, OpenBracket, CloseBracket, Eof, NewLine
  37.     }
  38.  
  39.     struct Token
  40.     {
  41.         public TokenType Type;
  42.         public string Datum;
  43.     }
  44.  
  45.     //Will choke on non-ASCII characters. TODO: Unicode
  46.     class Lexer
  47.     {
  48.         private readonly StreamReader _stream;
  49.         private uint _lineNumber = 1;
  50.         private uint _columnNumber = 0;
  51.  
  52.         public Lexer(StreamReader stream)
  53.         {
  54.             _stream = stream;
  55.         }
  56.  
  57.         private bool IsEof()
  58.         {
  59.             return _stream.Peek() == -1;
  60.         }
  61.  
  62.         private int Read()
  63.         {
  64.             _columnNumber++;
  65.             if (_stream.Peek() == '\n')
  66.             {
  67.                 _lineNumber++;
  68.                 _columnNumber = 1;
  69.             }
  70.             return _stream.Read();
  71.         }
  72.  
  73.         private int Peek()
  74.         {
  75.             return _stream.Peek();
  76.         }
  77.  
  78.         public void Bail(string reason)
  79.         {
  80.             Console.WriteLine("Line {0} Col {1} -- {2}", _lineNumber, _columnNumber, reason);
  81.             throw new Exception();
  82.         }
  83.  
  84.         private Token? _peekToken = null;
  85.  
  86.         public Token PeekToken()
  87.         {
  88.             if (_peekToken == null)
  89.                 _peekToken = ReadToken();
  90.             return (Token)_peekToken;
  91.         }
  92.  
  93.         public Token ReadToken()
  94.         {
  95.             if (_peekToken != null)
  96.             {
  97.                 var ret = _peekToken;
  98.                 _peekToken = null;
  99.                 return (Token)ret;
  100.             }
  101.  
  102.             //Skip Whitespace
  103.             int @byte;
  104.             do
  105.             {
  106.                 @byte = Read();
  107.                 if (@byte == -1)
  108.                     return new Token { Type = TokenType.Eof };
  109.                 //Skip comments
  110.                 if (@byte == ';')
  111.                     while (@byte != '\n' && @byte != -1)
  112.                         @byte = Read();
  113.             } while (Char.IsWhiteSpace((char)@byte) && @byte != '\n');
  114.  
  115.             if (@byte == '[')
  116.                 return new Token { Type = TokenType.OpenBracket };
  117.             if (@byte == ']')
  118.                 return new Token { Type = TokenType.CloseBracket };
  119.             if (@byte == '+')
  120.                 return new Token { Type = TokenType.Plus };
  121.             if (@byte == ',')
  122.                 return new Token { Type = TokenType.Comma };
  123.             if (@byte == '\n')
  124.                 return new Token { Type = TokenType.NewLine };
  125.             if (@byte == ':')
  126.             {
  127.                 var token = new Token { Type = TokenType.Label };
  128.                 if (IsEof() || !Char.IsLetter((char)Peek()))
  129.                 {
  130.                     Bail("Lexer: Label with invalid name (or name is not present)");
  131.                 }
  132.                 while (!IsEof() && Char.IsLetterOrDigit((char)Peek()))
  133.                 {
  134.                     token.Datum += (char)Read();
  135.                 }
  136.                 return token;
  137.             }
  138.             if (Char.IsNumber((char)@byte))
  139.             {
  140.                 var token = new Token { Type = TokenType.Number, Datum = ((char)@byte).ToString() };
  141.  
  142.                 //Hexadecimal
  143.                 if (@byte == '0' && Peek() == 'x')
  144.                 {
  145.                     token.Datum += (char)Read();
  146.                     while (!IsEof() &&
  147.                            (('0' <= Peek() && Peek() <= '9') ||
  148.                             ('a' <= Peek() && Peek() <= 'f') ||
  149.                             ('A' <= Peek() && Peek() <= 'F')))
  150.                         token.Datum += (char)Read();
  151.                     if (token.Datum == "0x")
  152.                         Bail("Lexer: Bare hexadecimal prefix (0x)");
  153.                     return token;
  154.                 }
  155.  
  156.                 //Binary
  157.                 if (@byte == '0' && Peek() == 'b')
  158.                 {
  159.                     token.Datum += (char)Read();
  160.                     while (!IsEof() && (Peek() == '0' || Peek() == '1'))
  161.                         token.Datum += (char)Read();
  162.                     if (token.Datum == "0b")
  163.                         Bail("Lexer: Bare binary prefix (0b)");
  164.                     return token;
  165.                 }
  166.  
  167.                 //Decimal
  168.                 while (!IsEof() && Char.IsNumber((char)Peek()))
  169.                     token.Datum += (char)Read();
  170.                 return token;
  171.             }
  172.             if (Char.IsLetter((char)@byte))
  173.             {
  174.                 var token = new Token { Type = TokenType.Word, Datum = ((char)@byte).ToString() };
  175.                 while (!IsEof() && Char.IsLetterOrDigit((char)Peek()))
  176.                     token.Datum += (char)Read();
  177.                 return token;
  178.             }
  179.             Bail(string.Format("Lexer: Unknown character {0} in stream", (char)@byte));
  180.             return new Token();
  181.         }
  182.     }
  183.  
  184.     enum InstructionOpcode
  185.     {
  186.  
  187.     }
  188.  
  189.     enum Register
  190.     {
  191.         A = 0, B = 1, C = 2, X = 3, Y = 4, Z = 5, I = 6, J = 7,
  192.         POP = 0x18, PEEK = 0x19, PUSH = 0x1a,
  193.         SP = 0x1b, PC = 0x1c, O = 0x1d,
  194.         Number = -1,
  195.         Label = -2
  196.     }
  197.  
  198.     class Parser
  199.     {
  200.         private readonly Dictionary<string, ushort> _opCodes = new Dictionary<string, ushort>
  201.         {
  202.             {"SET", 1},
  203.             {"ADD", 2},
  204.             {"SUB", 3},
  205.             {"MUL", 4},
  206.             {"DIV", 5},
  207.             {"MOD", 6},
  208.             {"SHL", 7},
  209.             {"SHR", 8},
  210.             {"AND", 9},
  211.             {"BOR", 0xa},
  212.             {"XOR", 0xb},
  213.             {"IFE", 0xc},
  214.             {"IFN", 0xd},
  215.             {"IFG", 0xe},
  216.             {"IFB", 0xf}
  217.         };
  218.  
  219.         private readonly Dictionary<string, int> _registers = new Dictionary<string, int>
  220.         {
  221.             {"A", 0},
  222.             {"B", 1},
  223.             {"C", 2},
  224.             {"X", 3},
  225.             {"Y", 4},
  226.             {"Z", 5},
  227.             {"I", 6},
  228.             {"J", 7}
  229.         };
  230.  
  231.         //Addressing Modes
  232.         //(Using a static class for scoping purposes. It is evil and you should never do it.)
  233.         private static class AddressingMode
  234.         {
  235.             public const int Register = 0; //0x00-0x07, register
  236.             public const int IndirectRegister = 0x08; //0x08-0x0f, [register]
  237.             public const int IndexedRegister = 0x10; //0x10-0x17, [register + next word]
  238.             //0x18 - 0x1d
  239.             public static readonly Dictionary<string, int> SpecialRegisters = new Dictionary<string, int>
  240.             {
  241.                 {"POP", 0x18},
  242.                 {"PEEK", 0x19},
  243.                 {"PUSH", 0x1a},
  244.                 {"SP", 0x1b},
  245.                 {"PC", 0x1c},
  246.                 {"O", 0x1d}
  247.             };
  248.             public const int MemoryLocation = 0x1e; //0x1e, [next word]
  249.             public const int LiteralNumber = 0x1f; //0x1f, next word (literal)
  250.             public const int SmallLiteral = 0x20; //0x20-0x3f, literal value 0x00-0x1f (literal)
  251.         }
  252.  
  253.         // Bookkeeping
  254.         private readonly Lexer _lexer;
  255.         private readonly Dictionary<string, int> _labels = new Dictionary<string, int>();
  256.         private readonly Dictionary<string, List<int>> _backRefsToDo = new Dictionary<string, List<int>>();
  257.  
  258.  
  259.         // Public Methods
  260.         public Parser(Lexer lexer)
  261.         {
  262.             _lexer = lexer;
  263.         }
  264.  
  265.         public ushort[] Parse()
  266.         {
  267.             return DoTheThing();
  268.         }
  269.  
  270.         // Everything below this point relates to parsing
  271.  
  272.         //Decimal or Hexadecimal or Binary
  273.         private ushort parseNumber()
  274.         {
  275.             return parseNumber(_lexer.ReadToken());
  276.         }
  277.         private ushort parseNumber(Token token)
  278.         {
  279.             if (token.Type != TokenType.Number)
  280.                 _lexer.Bail("Expected a number here.");
  281.  
  282.             if (token.Datum.Length > 2 && token.Datum[0] == '0' && token.Datum[1] == 'b')
  283.             {
  284.                 //Binary Number!
  285.                 return Convert.ToUInt16(token.Datum.Substring(2), 2); // Strip two character prefix, Base 2
  286.             }
  287.             else if (token.Datum.Length > 2 && token.Datum[0] == '0' && token.Datum[1] == 'x')
  288.             {
  289.                 //Hexadecimal Number!
  290.                 //Strip two character prefix.
  291.                 return ushort.Parse(token.Datum.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
  292.             }
  293.             else
  294.             {
  295.                 //Decimal Number!
  296.                 return ushort.Parse(token.Datum);
  297.             }
  298.         }
  299.  
  300.         private bool isLabel(Token token)
  301.         {
  302.             //Make sure a label doesn't use a reserved word!
  303.             return (token.Type == TokenType.Word && !_registers.ContainsKey(token.Datum) &&
  304.                     !AddressingMode.SpecialRegisters.ContainsKey(token.Datum));
  305.         }
  306.  
  307.         private bool isRegister(Token token)
  308.         {
  309.             return token.Type == TokenType.Word && _registers.ContainsKey(token.Datum);
  310.         }
  311.  
  312.         private bool isSpecialRegister(Token token)
  313.         {
  314.             return token.Type == TokenType.Word && AddressingMode.SpecialRegisters.ContainsKey(token.Datum);
  315.         }
  316.  
  317.         //If label is not avaliable yet, we'll add it as a to-do in _backRefsToDo
  318.         private void insertLabel(ref List<ushort> outputProgramCode, string label)
  319.         {
  320.             label = label.ToUpper();
  321.             if (_labels.ContainsKey(label))
  322.             {
  323.                 //We already know the label, simple and easy.
  324.                 outputProgramCode.Add((ushort)_labels[label]);
  325.                 return;
  326.             }
  327.  
  328.             //We don't know the label, insert it as a to-do
  329.  
  330.             if (!_backRefsToDo.ContainsKey(label))
  331.                 _backRefsToDo[label] = new List<int>();
  332.  
  333.             _backRefsToDo[label].Add(outputProgramCode.Count); //Insert current position
  334.             outputProgramCode.Add(0xFFFF); //Add a sentinel to the output, which we'll overwrite later.
  335.         }
  336.  
  337.         private Token ExpectToken(string errorMessage, params TokenType[] type)
  338.         {
  339.             var token = _lexer.ReadToken();
  340.             if (!type.Contains(token.Type))
  341.                 _lexer.Bail(errorMessage);
  342.             return token;
  343.         }
  344.  
  345.         private Token ExpectToken(string errorMessage, params Func<Token, bool>[] p)
  346.         {
  347.             var token = _lexer.ReadToken();
  348.             if (!p.Select(x => x(token)).Contains(true))
  349.                 _lexer.Bail(errorMessage);
  350.             return token;
  351.         }
  352.  
  353.         //Number or Register or [ Register ] or [ Number ] or [ Register + Number ]
  354.         //Returns Value: The appropriate Loc for that adressing scheme
  355.         //Appends words to the end of the program
  356.         private int parseAdressingScheme(ref List<ushort> outputProgramCode)
  357.         {
  358.             var token = _lexer.ReadToken();
  359.             switch (token.Type)
  360.             {
  361.                 case TokenType.Number:
  362.                     // A simple number literal.
  363.                     // If the number is less than 0x20, we can use the short version.
  364.                     {
  365.                         ushort number = parseNumber(token);
  366.                         if (number < AddressingMode.SmallLiteral)
  367.                             return number + AddressingMode.SmallLiteral;
  368.                         else
  369.                         {
  370.                             outputProgramCode.Add(number);
  371.                             return AddressingMode.LiteralNumber;
  372.                         }
  373.                     }
  374.                 case TokenType.Word:
  375.                     // We expect a word from either _register (A,B,C,X,...) or SpecialRegisters (POP, PEEK, ...) or a label
  376.                     token.Datum = token.Datum.ToUpper();
  377.                     if (isSpecialRegister(token))
  378.                     {
  379.                         return AddressingMode.SpecialRegisters[token.Datum];
  380.                     }
  381.                     else if (isRegister(token))
  382.                     {
  383.                         return _registers[token.Datum];
  384.                     }
  385.                     else if (isLabel(token))
  386.                     {
  387.                         insertLabel(ref outputProgramCode, token.Datum);
  388.                         return AddressingMode.LiteralNumber;
  389.                     }
  390.                     _lexer.Bail("Unknown Word: Expected name of register or special register or label");
  391.                     return -1;
  392.                 case TokenType.OpenBracket:
  393.                     //Here the possibilities are:
  394.                     // [ Number ]
  395.                     // [ Number + Register ]
  396.                     // [ Register ]
  397.                     // [ Register + Number ]
  398.                     // [ Label ]
  399.                     // [ Label + Register ]
  400.                     // [ Register + Label ]
  401.                     {
  402.                         if (_lexer.PeekToken().Type == TokenType.Number)
  403.                         {
  404.                             // [ Number ] OR [ Number + Register ]
  405.                             ushort number = parseNumber();
  406.  
  407.                             var thirdToken = _lexer.ReadToken();
  408.                             if (thirdToken.Type == TokenType.CloseBracket)
  409.                             {
  410.                                 // [ Number ]
  411.                                 outputProgramCode.Add(number);
  412.                                 return AddressingMode.MemoryLocation;
  413.                             }
  414.                             else if (thirdToken.Type == TokenType.Plus)
  415.                             {
  416.                                 // [ Number + Register ]
  417.                                 var registerToken = _lexer.ReadToken(); //fourth token
  418.                                 var closeBracketToken = _lexer.ReadToken(); //fifth token
  419.  
  420.                                 //Foruth needs to be a register and Fifth needs to be a "]":
  421.                                 if (!isRegister(registerToken) || closeBracketToken.Type != TokenType.CloseBracket)
  422.                                     _lexer.Bail("Expected a [ Number + Register ] here, no idea what I got.");
  423.  
  424.                                 outputProgramCode.Add(number);
  425.                                 return AddressingMode.IndexedRegister + _registers[registerToken.Datum];
  426.                             }
  427.                             else
  428.                             {
  429.                                 _lexer.Bail("Expected ] or + (as part of [Number] or [Number + Register])");
  430.                                 return -1;
  431.                             }
  432.                         }
  433.                         else if (isRegister(_lexer.PeekToken()))
  434.                         {
  435.                             // Is a Register!
  436.                             // [ Register ] OR [ Register + Number ] OR [ Register + Label ]
  437.                             string registerName = _lexer.ReadToken().Datum;
  438.                             int registerNumber = _registers[registerName];
  439.  
  440.                             var thirdToken = _lexer.ReadToken();
  441.                             if (thirdToken.Type == TokenType.CloseBracket)
  442.                             {
  443.                                 // [ Register ]
  444.                                 return AddressingMode.IndirectRegister + registerNumber;
  445.                             }
  446.                             else if (thirdToken.Type == TokenType.Plus)
  447.                             {
  448.                                 // [ Register + Number ] OR [ Register + Label ]
  449.  
  450.                                 if (_lexer.PeekToken().Type == TokenType.Number)
  451.                                 {
  452.                                     // [ Register + Number ]
  453.  
  454.                                     var number = parseNumber();
  455.                                     outputProgramCode.Add(number);
  456.  
  457.                                     ExpectToken("Expected a ] here", TokenType.CloseBracket);
  458.  
  459.                                     return AddressingMode.IndexedRegister + registerNumber;
  460.                                 }
  461.                                 else if (isLabel(_lexer.PeekToken()))
  462.                                 {
  463.                                     // [ Register + Label ]
  464.  
  465.                                     var label = _lexer.ReadToken().Datum;
  466.                                     insertLabel(ref outputProgramCode, label);
  467.  
  468.                                     ExpectToken("Expected a ] here", TokenType.CloseBracket);
  469.  
  470.                                     return AddressingMode.IndexedRegister + registerNumber;
  471.                                 }
  472.                                 _lexer.Bail("Expected number or label after + (as part of [Register + Number])");
  473.                                 return -1;
  474.                             }
  475.                             else
  476.                             {
  477.                                 _lexer.Bail("Expected ] or + (as part of [Register] or [Register + Number])");
  478.                                 return -1;
  479.                             }
  480.                         }
  481.                         else if (isLabel(_lexer.PeekToken()))
  482.                         {
  483.                             // [ Label ] OR  [ Label + Register ]
  484.                             string label = _lexer.ReadToken().Datum;
  485.  
  486.                             var thirdToken = _lexer.ReadToken();
  487.                             if (thirdToken.Type == TokenType.CloseBracket)
  488.                             {
  489.                                 // [ Label ]
  490.                                 insertLabel(ref outputProgramCode, label);
  491.                                 return AddressingMode.MemoryLocation;
  492.                             }
  493.                             else if (thirdToken.Type == TokenType.Plus)
  494.                             {
  495.                                 // [ Label + Register ]
  496.                                 var registerToken = _lexer.ReadToken(); //fourth token
  497.                                 var closeBracketToken = _lexer.ReadToken(); //fifth token
  498.  
  499.                                 //Foruth needs to be a register and Fifth needs to be a "]":
  500.                                 if (!isRegister(registerToken) || closeBracketToken.Type != TokenType.CloseBracket)
  501.                                     _lexer.Bail("Expected a [ Label + Register ] here, no idea what I got.");
  502.  
  503.                                 insertLabel(ref outputProgramCode, label);
  504.                                 return AddressingMode.IndexedRegister + _registers[registerToken.Datum];
  505.                             }
  506.                             else
  507.                             {
  508.                                 _lexer.Bail("Expected ] or + (as part of [Label] or [Label + Register])");
  509.                                 return -1;
  510.                             }
  511.                         }
  512.                         else
  513.                         {
  514.                             _lexer.Bail("Expected Register or Number (as part of [Register] or [Number] or [Register + Number])");
  515.                             return -1;
  516.                         }
  517.                     }
  518.                     _lexer.Bail("ICE: Should never reach here");
  519.                     return -1;
  520.                 default:
  521.                     _lexer.Bail("Expected addressing scheme (Number or Register or [Register] or [Number] or [Register + Number]) here, not whatever was here.");
  522.                     return -1;
  523.             }
  524.         }
  525.  
  526.         //a basic instruction has the format: bbbbbbaaaaaaoooo
  527.         private ushort ConstructInstruction(int o, int a, int b)
  528.         {
  529.             return (ushort)((b << 10) | ((a & 0x3F) << 4) | (o & 0xF));
  530.         }
  531.  
  532.         //Grammar for a line: OPTIONAL_LABEL OPCODE ADDRESSINGSCHEME "," ADDRESSINGSCHEME "\n"
  533.         //With an exception: OPTIONAL_LABEL "JSR" ADDRESSINGSCHEME "\n"
  534.         private ushort[] DoTheThing()
  535.         {
  536.             var outputProgramCode = new List<ushort>();
  537.  
  538.             while (true)
  539.             {
  540.                 //Skip all newlines
  541.                 while (_lexer.PeekToken().Type == TokenType.NewLine)
  542.                 {
  543.                     _lexer.ReadToken();
  544.                 }
  545.  
  546.                 //If we're at the end of the file, we're done!
  547.                 if (_lexer.PeekToken().Type == TokenType.Eof)
  548.                     return outputProgramCode.ToArray();
  549.  
  550.                 //Begin parsing current instruction
  551.                 var currentInstructionLocation = (ushort)outputProgramCode.Count;
  552.                 outputProgramCode.Add(0xBAAD); //Temporary sentinel
  553.  
  554.                 //The first thing we expect in a line of assembler is an optional label.
  555.                 if (_lexer.PeekToken().Type == TokenType.Label)
  556.                 {
  557.                     var labelName = _lexer.ReadToken().Datum.ToUpper();
  558.  
  559.                     //Add to list of labels so we can backreference it later
  560.                     _labels.Add(labelName, currentInstructionLocation);
  561.  
  562.                     //Sort out forward references to this label.
  563.                     if (_backRefsToDo.ContainsKey(labelName))
  564.                         foreach (var backref in _backRefsToDo[labelName])
  565.                             outputProgramCode[backref] = currentInstructionLocation;
  566.                 }
  567.  
  568.                 var opcodeToken = ExpectToken("Parser: Expected Instruction Opcode", TokenType.Word);
  569.                 var opcode = opcodeToken.Datum.ToUpper();
  570.  
  571.                 if (opcode == "JSR")
  572.                 {
  573.                     int addressingMode = parseAdressingScheme(ref outputProgramCode);
  574.                     ExpectToken("Expected end of line", TokenType.NewLine, TokenType.Eof);
  575.  
  576.                     outputProgramCode[currentInstructionLocation] = ConstructInstruction(0, 0x01, addressingMode);
  577.                 }
  578.                 else if (_opCodes.ContainsKey(opcode))
  579.                 {
  580.                     int addressingModeA = parseAdressingScheme(ref outputProgramCode);
  581.                     ExpectToken("Expected comma", TokenType.Comma);
  582.                     int addressingModeB = parseAdressingScheme(ref outputProgramCode);
  583.                     ExpectToken("Expected end of line", TokenType.NewLine, TokenType.Eof);
  584.  
  585.                     outputProgramCode[currentInstructionLocation] = ConstructInstruction(_opCodes[opcode], addressingModeA, addressingModeB);
  586.                 }
  587.                 else
  588.                     _lexer.Bail("Parser: Invalid Opcode");
  589.             }
  590.  
  591.         }
  592.     }
  593.  
  594.     class Program
  595.     {
  596.         private int lineNumber = 0;
  597.  
  598.         private static void TestLexer()
  599.         {
  600.             string line;
  601.  
  602.             using (var file = new StreamReader(@"C:\Users\awood\Documents\work\0x10c\Assembler2\a.s"))
  603.             {
  604.                 var lexer = new Lexer(file);
  605.                 while (lexer.PeekToken().Type != TokenType.Eof)
  606.                 {
  607.                     var token = lexer.ReadToken();
  608.                     Console.WriteLine("{0} {1}", token.Type.ToString(), token.Datum);
  609.                 }
  610.             }
  611.             Console.ReadLine();
  612.         }
  613.  
  614.         private static void TestParser()
  615.         {
  616.             using (var file = new StreamReader(@"C:\Users\awood\Documents\work\0x10c\Assembler2\a.s"))
  617.             {
  618.                 var lexer = new Lexer(file);
  619.                 var parser = new Parser(lexer);
  620.  
  621.                 var result = parser.Parse();
  622.                 foreach (var w in result)
  623.                 {
  624.                     Console.Write("{0:X4} ", w);
  625.                 }
  626.             }
  627.             Console.WriteLine();
  628.             Console.ReadLine();
  629.         }
  630.  
  631.         static void Main(string[] args)
  632.         {
  633.             TestParser();
  634.         }
  635.     }
  636. }