Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Sloth - Lexer.cs

Lexer.cs

Caricato da: Totem
Scarica il programma completo

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. using System.IO;
  7.  
  8. namespace Sloth
  9. {
  10.     public class InvalidLexemeException : InterpreterException
  11.     {
  12.         public InvalidLexemeException(String message, Int32 lineNumber) : base(message, lineNumber) { }
  13.     }
  14.  
  15.     public enum TokenType
  16.     {
  17.         Identifier,
  18.         Label,
  19.         Register,
  20.         LiteralConstant,
  21.         OpenBracket,
  22.         ClosedBracket,
  23.         Sign,
  24.         Separator,
  25.         Sharp,
  26.         NewLine,
  27.         LiteralString,
  28.         None
  29.     }
  30.  
  31.     [System.Diagnostics.DebuggerDisplay("{ToString()}")]
  32.     public struct Token : IEquatable<Token>
  33.     {
  34.         private static Token empty = new Token(TokenType.None, String.Empty);
  35.         public static Token Empty { get { return empty; } }
  36.  
  37.         public TokenType Type { get; set; }
  38.         public String Lexeme { get; set; }
  39.  
  40.         public Token(TokenType type, String lexeme) : this()
  41.         {
  42.             this.Type = type;
  43.             this.Lexeme = lexeme;
  44.         }
  45.  
  46.         public override string ToString()
  47.         {
  48.             return String.Format("[{0}, {1}]", this.Type.ToString(), this.Lexeme);
  49.         }
  50.  
  51.         public bool Equals(Token other)
  52.         {
  53.             return (this.Lexeme == other.Lexeme) && (this.Type == other.Type);
  54.         }
  55.     }
  56.  
  57.     public class TokenList : List<Token> { }
  58.  
  59.     public class TokenizationRuleSet : Dictionary<Regex, TokenType> { }
  60.  
  61.     public class SymbolSet : Dictionary<Char, TokenType> { }
  62.  
  63.     public class Lexer
  64.     {
  65.         protected Char commentChar;
  66.         private Int32 lineNumber;
  67.  
  68.         protected TokenizationRuleSet Rules { get; set; }
  69.         protected SymbolSet Symbols { get; set; }
  70.         protected List<Char> IgnoredCharacters { get; set; }
  71.  
  72.         public TokenList Output { get; protected set; }
  73.  
  74.         public Lexer()
  75.         {
  76.             this.Output = new TokenList();
  77.             this.IgnoredCharacters = new List<Char>() { ' ', '\t', '\f', '\r', '\v' };
  78.             this.commentChar = ';';
  79.  
  80.             this.Symbols = new SymbolSet()
  81.             {
  82.                 { ',', TokenType.Separator },
  83.                 { '(', TokenType.OpenBracket },
  84.                 { ')', TokenType.ClosedBracket },
  85.                 { '+', TokenType.Sign },
  86.                 { '-', TokenType.Sign },
  87.                 { '#', TokenType.Sharp }
  88.             };
  89.  
  90.             this.Rules = new TokenizationRuleSet()
  91.             {
  92.                 { new Regex("^[\\w_]+:$", RegexOptions.IgnoreCase), TokenType.Label },
  93.                 { new Regex("^(A|D)[0-7]$", RegexOptions.IgnoreCase), TokenType.Register },
  94.                 { new Regex("^(\\d+|\\$[0-9A-F]+)(\\.(B|W|L))?$", RegexOptions.IgnoreCase), TokenType.LiteralConstant },
  95.                 { new Regex("^(#)?\\w+(\\.(B|W|L))?$", RegexOptions.IgnoreCase), TokenType.Identifier },
  96.                 { new Regex("^.+$"), TokenType.LiteralString }
  97.             };
  98.         }
  99.  
  100.         public void Tokenize(String code)
  101.         {
  102.             StringBuilder purgedCodeBuilder = new StringBuilder();
  103.             StringBuilder buffer = new StringBuilder();
  104.  
  105.             this.Output.Clear();
  106.            
  107.             lineNumber = 1;
  108.  
  109.             // Elimina i commenti
  110.             Boolean commentOpen = false;
  111.             foreach (Char c in code)
  112.             {
  113.                 if (c == commentChar)
  114.                     commentOpen = true;
  115.                 else if (c == '\n')
  116.                     commentOpen = false;
  117.  
  118.                 if (!commentOpen)
  119.                     purgedCodeBuilder.Append(c);
  120.             }
  121.  
  122.             String purgedCode = purgedCodeBuilder.ToString();
  123.             Boolean stringOpen = false;
  124.             foreach (Char c in purgedCode)
  125.             {
  126.                 if (c == '\'')
  127.                 {
  128.                     stringOpen = !stringOpen;
  129.                     if (stringOpen == false)
  130.                     {
  131.                         this.Output.Add(new Token(TokenType.LiteralString, buffer.ToString().Trim('\'')));
  132.                         buffer.Clear();
  133.                         continue;
  134.                     }
  135.                 }
  136.  
  137.                 if (!stringOpen) // legge token solo quando una c'è una stringa aperta
  138.                 {
  139.                     if (c == '\n')
  140.                     {
  141.                         this.AddToken(buffer);
  142.                         lineNumber++;
  143.                         this.Output.Add(new Token(TokenType.NewLine, "\n"));
  144.                     }
  145.                     else if (this.IgnoredCharacters.Contains(c))
  146.                         this.AddToken(buffer);
  147.                     else if (this.Symbols.ContainsKey(c))
  148.                     {
  149.                         this.AddToken(buffer);
  150.                         this.Output.Add(new Token(this.Symbols[c], c.ToString()));
  151.                     }
  152.                     else
  153.                         buffer.Append(c);
  154.                 }
  155.                 else
  156.                     buffer.Append(c);
  157.             }
  158.  
  159.             this.AddToken(buffer);
  160.             buffer = null;
  161.         }
  162.  
  163.         public void TokenizeFromFile(String path)
  164.         {
  165.             this.Tokenize(File.ReadAllText(path));
  166.         }
  167.  
  168.         private Token ScanLexeme(String buffer)
  169.         {
  170.             if (String.IsNullOrEmpty(buffer))
  171.                 return Token.Empty;
  172.  
  173.             foreach (Regex expression in this.Rules.Keys)
  174.                 if (expression.IsMatch(buffer))
  175.                     return new Token(this.Rules[expression], buffer);
  176.  
  177.             throw new InvalidLexemeException(String.Format("Il lessema '{0}' non è valido.", buffer), lineNumber);
  178.         }
  179.  
  180.         private void AddToken(StringBuilder buffer)
  181.         {
  182.             String str = buffer.ToString();
  183.             Token token = this.ScanLexeme(str);
  184.             if (!token.Equals(Token.Empty))
  185.                 this.Output.Add(token);
  186.             buffer.Clear();
  187.         }
  188.     }
  189. }