forked from stevedonovan/cs-repl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
prepro.cs
125 lines (113 loc) · 4.59 KB
/
prepro.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
using System;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;
public class MacroEntry {
public string Subst;
public string[] Parms;
}
public class MacroSubstitutor {
Hashtable macroTable = new Hashtable();
public void AddMacro(string name, string subst, string[] parms) {
MacroEntry me = new MacroEntry();
string pstr = "";
if (parms != null)
pstr = string.Join(",",parms);
me.Subst = subst;
me.Parms = parms;
macroTable[name] = me;
}
public void RemoveMacro(string name) {
macroTable[name] = null;
}
public MacroEntry Lookup(string s) {
return (MacroEntry)macroTable[s];
}
static Regex iden = new Regex(@"[a-zA-Z_]\w*");
public string ReplaceParms(MacroEntry me, string[] actual_parms) {
Match m;
int istart = 0;
string subst = me.Subst;
while ((m = iden.Match(subst,istart)) != Match.Empty) {
int idx = Array.IndexOf(me.Parms,m.Value);
int len = m.Length;
if (idx != -1) {
string actual = actual_parms[idx];
// A _single_ # before a token means the 'stringizing' operator
if (m.Index > 0 && subst[m.Index-1] == '#') {
// whereas ## means 'token-pasting'! #s will be removed later!
if (! (m.Index > 1 && subst[m.Index-2] == '#'))
actual = '\"' + actual + '\"';
}
subst = iden.Replace(subst,actual,1,istart);
len = actual.Length;
}
istart = m.Index + len;
}
subst = subst.Replace("#","");
return subst;
}
public string Substitute(string str) {
Match m;
int istart = 0;
while ((m = iden.Match(str,istart)) != Match.Empty) {
MacroEntry me = (MacroEntry)macroTable[m.Value];
if (me != null) {
string subst = me.Subst;
if (me.Parms != null) {
int i = m.Index + m.Length; // points to char just beyond match
while (i < str.Length && str[i] != '(')
i++;
i++; // just past '('
int parenDepth = 1;
string [] actuals = new string[me.Parms.Length];
int idx = 0, isi = i;
while (parenDepth > 0 && i < str.Length) {
char ch = str[i];
if (parenDepth == 1 && (ch == ',' || ch == ')')) {
actuals[idx] = str.Substring(isi,i - isi);
idx++;
isi = i+1; // past ',' or ')'
}
// *fix 0.8 now understands commas within braces or square brackets (e.g. 'matrix' indexing)
if (ch == '(' || ch == '{' || ch == '[') parenDepth++; else
if (ch == ')' || ch == '}' || ch == ']') parenDepth--;
i++;
}
if (parenDepth != 0) {
return "**Badly formed macro call**";
}
subst = ReplaceParms(me,actuals);
istart = m.Index;
str = str.Remove(istart,i - istart);
str = str.Insert(istart,subst);
} else {
str = iden.Replace(str,subst,1,istart);
}
} else
istart = m.Index + m.Length;
}
return str;
}
static Regex define = new Regex(@"#def (\w+)($|\s+|\(.+\)\s+)(.+)");
public string ProcessLine(string line) {
Match m = define.Match(line);
if (m != Match.Empty) {
string [] parms = null;
string sym = m.Groups[1].ToString();
string subst = m.Groups[3].ToString();
string arg = m.Groups[2].ToString();
if (arg != "") {
arg = arg.ToString();
if (arg[0] == '(') {
arg = arg.TrimEnd(null);
arg = arg.Substring(1,arg.Length-2);
parms = arg.Split(new char[]{','});
}
}
AddMacro(sym,subst,parms);
return "";
} else
return Substitute(line);
}
}