1 //
2 // Copyright (c) 2010-2022 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using System.Globalization;
10 using System.IO;
11 using System.Linq;
12 using System.Text.RegularExpressions;
13 using Antmicro.Renode.Exceptions;
14 
15 namespace Antmicro.Renode.Utilities
16 {
17     public class VmemReader
18     {
19         // Implementation based on section 17.2.9 of
20         // http://staff.ustc.edu.cn/~songch/download/IEEE.1364-2005.pdf
VmemReader(ReadFilePath file)21         public VmemReader(ReadFilePath file)
22         {
23             this.file = file;
24         }
25 
GetIndexDataPairs()26         public IEnumerable<Tuple<long, ulong>> GetIndexDataPairs()
27         {
28             return GetMappedEnumerable(data =>
29             {
30                 if(UInt64.TryParse(data, NumberStyles.HexNumber, null, out var l))
31                 {
32                     return l;
33                 }
34                 else
35                 {
36                     throw new RecoverableException($"Invalid hexstring \"{data}\" at line {lineNumber}");
37                 }
38             });
39         }
40 
GetRawEnumerable()41         private IEnumerable<Tuple<long, string>> GetRawEnumerable()
42         {
43             if(started)
44             {
45                 yield break;
46             }
47             else
48             {
49                 started = true;
50             }
51             var matchEvaluator = new MatchEvaluator(MatchEvaluatorFunction);
52 
53             foreach(var line in File.ReadLines(file))
54             {
55                 lineNumber += 1;
56                 string dataLine;
57                 if(inMultilineComment)
58                 {
59                     var endOfComment = line.IndexOf("*/");
60                     if(line.Length > 0 && endOfComment != -1)
61                     {
62                         inMultilineComment = false;
63                         dataLine = line.Substring(endOfComment + 2);
64                     }
65                     else
66                     {
67                         continue;
68                     }
69                 }
70                 else
71                 {
72                     dataLine = regexComments.Replace(line, matchEvaluator);
73                 }
74 
75                 foreach(var e in ParseCommentless(dataLine))
76                 {
77                     yield return e;
78                 }
79             }
80         }
81 
GetMappedEnumerable(Func<string, T> mapping)82         private IEnumerable<Tuple<long, T>> GetMappedEnumerable<T>(Func<string, T> mapping)
83         {
84             return GetRawEnumerable().Select(e => new Tuple<long, T>(e.Item1, mapping(e.Item2)));
85         }
86 
MatchEvaluatorFunction(Match match)87         private string MatchEvaluatorFunction(Match match)
88         {
89             if(match.Length >= 2 && match.Value[1] == '*' && (match.Length == 2 || match.Value[match.Length - 2] != '*'))
90             {
91                 inMultilineComment = true;
92             }
93             return " ";
94         }
95 
ParseCommentless(string sub)96         private IEnumerable<Tuple<long, string>> ParseCommentless(string sub)
97         {
98             var words = sub.Split(whitespaces, StringSplitOptions.RemoveEmptyEntries);
99             foreach(var data in CheckForIndex(words))
100             {
101                 yield return new Tuple<long, string>(index, data);
102                 index += 1;
103             }
104         }
105 
CheckForIndex(IEnumerable<string> words)106         private IEnumerable<string> CheckForIndex(IEnumerable<string> words)
107         {
108             foreach(var word in words)
109             {
110                 if(word.StartsWith("@"))
111                 {
112                     if(Int64.TryParse(word.Substring(1), NumberStyles.HexNumber, null, out var idx))
113                     {
114                         index = idx;
115                     }
116                     else
117                     {
118                         throw new RecoverableException($"Invalid index \"{word}\" at line {lineNumber}");
119                     }
120                 }
121                 else
122                 {
123                     yield return word;
124                 }
125             }
126         }
127 
128         private static readonly char[] whitespaces = new char[] { ' ', '\n', '\t', '\f' };
129         private static readonly Regex regexComments = new Regex(@"/\*(.*?\*/|.*)|//.*");
130 
131         private bool started;
132         private bool inMultilineComment;
133         private long index;
134         private long lineNumber;
135 
136         private readonly string file;
137     }
138 }
139