|
1 | | -function S = matl_compile(S, F, L, pOutFile, cOutFile, verbose, isMatlab) |
| 1 | +function S = matl_compile(S, F, L, pOutFile, cOutFile, verbose, isMatlab, useTags) |
2 | 2 | % |
3 | 3 | % MATL compiler. Compiles into MATLAB code. |
4 | 4 | % Input: struct array with parsed statements. |
|
21 | 21 | % |
22 | 22 | % Luis Mendo |
23 | 23 |
|
24 | | -global indStepComp |
25 | | -global C |
| 24 | +global indStepComp C implicitInputBlock |
26 | 25 |
|
27 | 26 | indStepComp = 4; |
28 | 27 |
|
| 28 | +if verbose |
| 29 | + disp(' Generating compiled code') |
| 30 | +end |
| 31 | + |
29 | 32 | Fsource = {F.source}; % this field of `F` will be used often |
30 | 33 |
|
31 | 34 | % Possible improvement: preallocate for greater speed, and modify |
32 | 35 | % appendLines so that C doesn't dynamically grow |
33 | 36 | C = {}; % Cell array of strings. Each cell contains a line of compiled (MATLAB) code |
34 | 37 |
|
35 | | -if verbose |
36 | | - disp(' Generating compiled code') |
| 38 | +if useTags |
| 39 | + strongBegin = '<strong>'; |
| 40 | + strongEnd = '</strong>'; |
| 41 | +else |
| 42 | + strongBegin = ''; |
| 43 | + strongEnd = ''; |
37 | 44 | end |
38 | 45 |
|
| 46 | +% Define blocks of code that will be reused |
| 47 | +implicitInputBlock = {... |
| 48 | + 'if ~isempty(nin) && (numel(STACK)+nin(1)<1)' ... |
| 49 | + 'implInput = {};' ... |
| 50 | + 'for k = 1:1-numel(STACK)-nin(1)' ... |
| 51 | + 'implInput{k} = input(implicitInputPrompt,''s'');' ... |
| 52 | + 'assert(isempty(regexp(implInput{k}, ''^[^'''']*(''''[^'''']*''''[^'''']*)*[a-zA-Z]{2}'', ''once'')), ''MATL:runtime'', ''MATL run-time error: input not allowed'')' ... |
| 53 | + 'if isempty(implInput{k}), implInput{end} = []; else implInput{k} = eval(implInput{k}); end' ... |
| 54 | + 'end' ... |
| 55 | + 'STACK = [implInput STACK];' ... |
| 56 | + 'clear implInput k' ... |
| 57 | + 'end'}; |
| 58 | + |
39 | 59 | % Include function header |
40 | 60 | [~, name] = fileparts(cOutFile); |
41 | 61 | appendLines(['function ' name], 0) |
|
61 | 81 | appendLines('P = pi; Y = inf; N = NaN; M = -1; G = -1j;', 0) |
62 | 82 | % Constants to be used by function code |
63 | 83 | appendLines('defaultInputPrompt = ''> '';', 0); |
| 84 | +appendLines('implicitInputPrompt = ''> '';', 0); |
64 | 85 | % Predefine literals for functions |
65 | 86 | if ~isempty(S) |
66 | 87 | plf = cellstr(char(bsxfun(@plus, 'X0', [floor(0:.1:2.9).' repmat((0:9).',3,1)]))).'; % {'X0'...'Z9'} |
|
101 | 122 | case 'literal.logicalRowArray' |
102 | 123 | lit = strrep(strrep(S(n).source,'T','true,'),'F','false,'); |
103 | 124 | lit = ['[' lit(1:end-1) ']']; |
104 | | - appendLines(['STACK{end+1} = ' lit ';'], S(n).nesting) |
| 125 | + appendLines(['STACK{end+1} = ' lit ';'], S(n).nesting) |
| 126 | + case 'metaFunction.inSpec' |
| 127 | + appendLines('nin = 0;', S(n).nesting); |
| 128 | + appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input |
| 129 | + appendLines('S_IN = STACK{end}; STACK(end) = [];', S(n).nesting) |
| 130 | + case 'metaFunction.outSpec' |
| 131 | + appendLines('nin = 0;', S(n).nesting); |
| 132 | + appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input |
| 133 | + appendLines('S_OUT = STACK{end}; STACK(end) = [];', S(n).nesting) |
105 | 134 | case 'controlFlow.for' |
| 135 | + appendLines('nin = 0;', S(n).nesting); |
| 136 | + appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input |
106 | 137 | newLines{1} = sprintf('in = STACK{end}; STACK(end) = []; indFor%i = 0;', S(n).nesting); |
107 | 138 | newLines{2} = sprintf('for varFor%i = in', S(n).nesting); |
108 | 139 | appendLines(newLines, S(n).nesting) |
|
117 | 148 | newLines = sprintf('indDoWhile%i = indDoWhile%i+1;', S(n).nesting, S(n).nesting); |
118 | 149 | appendLines(newLines, S(n).nesting+1) |
119 | 150 | case 'controlFlow.while' % 'X`' |
| 151 | + appendLines('nin = 0;', S(n).nesting); |
| 152 | + appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input |
120 | 153 | newLines = { sprintf('indWhile%i = 0;', S(n).nesting) ... |
121 | 154 | sprintf('condWhile%i = STACK{end};', S(n).nesting) ... |
122 | 155 | 'STACK(end) = [];' ... |
|
125 | 158 | newLines = sprintf('indWhile%i = indWhile%i+1;', S(n).nesting, S(n).nesting); |
126 | 159 | appendLines(newLines, S(n).nesting+1) |
127 | 160 | case 'controlFlow.if' % '?' |
| 161 | + appendLines('nin = 0;', S(n).nesting); |
| 162 | + appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input |
128 | 163 | newLines = { 'in = STACK{end}; STACK(end) = [];' ... |
129 | 164 | 'if in' }; |
130 | 165 | appendLines(newLines, S(n).nesting); |
131 | 166 | case 'controlFlow.else' % '}' |
132 | 167 | appendLines('else', S(n).nesting) |
133 | 168 | case 'controlFlow.end' % ']' |
134 | 169 | if strcmp(S(S(n).from).type, 'controlFlow.doWhile') |
| 170 | + appendLines('nin = 0;', S(n).nesting); |
| 171 | + appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input |
135 | 172 | newLines = { sprintf('condDoWhile%i = STACK{end};', S(n).nesting) ... |
136 | 173 | 'STACK(end) = [];' ... |
137 | 174 | 'end' ... |
138 | 175 | sprintf('clear indDoWhile%i', S(n).nesting)}; |
139 | 176 | appendLines(newLines, S(n).nesting) |
140 | 177 | elseif strcmp(S(S(n).from).type, 'controlFlow.while') |
| 178 | + appendLines('nin = 0;', S(n).nesting); |
| 179 | + appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input |
141 | 180 | newLines = { sprintf('condWhile%i = STACK{end};', S(n).nesting) ... |
142 | 181 | 'STACK(end) = [];' ... |
143 | 182 | 'end' ... |
|
151 | 190 | newLines = 'end'; |
152 | 191 | appendLines(newLines, S(n).nesting); |
153 | 192 | else |
154 | | - error('MATL:compiler:internal', 'MATL internal error while compiling statement <strong>%s</strong>', S(n).source) |
| 193 | + error('MATL:compiler:internal', 'MATL internal error while compiling statement %s%s%s', strongBegin, S(n).source, strongEnd) |
155 | 194 | end |
156 | 195 | case 'controlFlow.conditionalBreak' |
| 196 | + appendLines('nin = 0;', S(n).nesting); |
| 197 | + appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input |
157 | 198 | appendLines('in = STACK{end}; STACK(end) = []; if in, break, end', S(n).nesting) |
158 | 199 | case 'controlFlow.conditionalContinue' |
| 200 | + appendLines('nin = 0;', S(n).nesting); |
| 201 | + appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input |
159 | 202 | appendLines('in = STACK{end}; STACK(end) = []; if in, continue, end', S(n).nesting) |
160 | 203 | case 'controlFlow.forValue' |
161 | 204 | k = S(S(n).from).nesting; |
|
169 | 212 | case 'function' |
170 | 213 | k = find(strcmp(S(n).source, Fsource), 1); % Fsource is guaranteed to contain unique entries. |
171 | 214 | if isempty(k) |
172 | | - error('MATL:compiler', 'MATL error while compiling: function <strong>%s</strong> in <a href="matlab: opentoline(''%s'', %i)">statement number %i</a> not defined in MATL', S(n).source, pOutFile, n, n) |
| 215 | + if useTags |
| 216 | + error('MATL:compiler', 'MATL error while compiling: function %s%s%s in <a href="matlab: opentoline(''%s'', %i)">statement number %i</a> not defined in MATL', strongBegin, S(n).source, strongEnd, pOutFile, n, n) |
| 217 | + else |
| 218 | + error('MATL:compiler', 'MATL error while compiling: function %s%s%s in statement number %i not defined in MATL', strongBegin, S(n).source, strongEnd, n) |
| 219 | + end |
173 | 220 | end |
174 | 221 | appendLines(funWrap(F(k).minIn, F(k).maxIn, F(k).defIn, F(k).minOut, F(k).maxOut, F(k).defOut, ... |
175 | 222 | F(k).consumeInputs, F(k).wrap, F(k).body), S(n).nesting) |
176 | 223 | C = [C strcat(blanks(indStepComp*S(n).nesting), newLines)]; |
177 | 224 | otherwise |
178 | | - error('MATL:compiler:internal', 'MATL internal error while compiling statement <strong>%s</strong>: unrecognized statement type', S(n).source) |
| 225 | + error('MATL:compiler:internal', 'MATL internal error while compiling statement %s%s%s: unrecognized statement type', strongBegin, S(n).source, strongEnd) |
179 | 226 | end |
180 | 227 | end |
181 | 228 |
|
|
192 | 239 | appendLines('% Define subfunctions', 0) |
193 | 240 | appendLines('', 0) |
194 | 241 | appendLines({... |
195 | | - 'function y = num2str(varargin)'; |
196 | | - 'x = varargin{1}; x = reshape(x, size(x,1),[]);'; |
197 | | - 'if nargin==1 || ischar(varargin{1}) || isnumeric(varargin{2})'; % normal `num2str` function |
198 | | - 'y = builtin(''num2str'', varargin{:});'; |
199 | | - 'else'; % interception |
200 | | - 'fmt = varargin{2}; y = sprintf([fmt ''\n''], x.''); y = regexp(y, ''\n'', ''split''); y = y(1:end-1).'';'; |
201 | | - 'y = cellfun(@fliplr, y, ''uniformoutput'', false); y = char(y); y = fliplr(y);'; |
202 | | - 'y = reshape(y.'',[],size(x,1)).''; y = strtrim(y);'; |
203 | | - 'end'; |
| 242 | + 'function y = num2str(varargin)' ... |
| 243 | + 'x = varargin{1}; x = reshape(x, size(x,1),[]);' ... |
| 244 | + 'if nargin==1 || ischar(varargin{1}) || isnumeric(varargin{2}) || any(imag(x(:)))' ... % normal `num2str` function |
| 245 | + 'y = builtin(''num2str'', varargin{:});' ... |
| 246 | + 'else' ... % interception |
| 247 | + 'fmt = varargin{2}; y = sprintf([fmt ''\n''], x.''); y = regexp(y, ''\n'', ''split''); y = y(1:end-1).'';' ... |
| 248 | + 'y = cellfun(@fliplr, y, ''uniformoutput'', false); y = char(y); y = fliplr(y);' ... |
| 249 | + 'y = reshape(y.'',[],size(x,1)).''; y = strtrim(y);' ... |
| 250 | + 'end' ... |
204 | 251 | 'end'}, 0) |
205 | 252 | % im2col |
206 | 253 | appendLines('', 0) |
207 | 254 | appendLines({... |
208 | | - 'function y = im2col(varargin)'; |
209 | | - 'argin1 = varargin{1}; argin1 = reshape(argin1, size(argin1,1), []);'; |
210 | | - 'y = builtin(''im2col'', argin1, varargin{2:end});'; |
| 255 | + 'function y = im2col(varargin)' ... |
| 256 | + 'argin1 = varargin{1}; argin1 = reshape(argin1, size(argin1,1), []);' ... |
| 257 | + 'y = builtin(''im2col'', argin1, varargin{2:end});' ... |
211 | 258 | 'end'}, 0) |
212 | 259 | end |
213 | 260 |
|
|
239 | 286 | % Code generated at the beginning of functions: check S_IN and S_OUT, |
240 | 287 | % get inputs, prepare outputs, consume inputs if applicable. |
241 | 288 | % `consume` indicates if inputs should be removed from the stack |
| 289 | +global implicitInputBlock |
242 | 290 | newLines = { ... |
243 | 291 | sprintf('if isempty(S_IN), S_IN = %s; end', defIn) ... |
244 | 292 | sprintf('if isnumeric(S_IN) && numel(S_IN) == 1, if S_IN < %s || S_IN > %s, error(''MATL:runner'', ''MATL run-time error: incorrect input specification''), end', minIn, maxIn) ... |
245 | 293 | sprintf('elseif islogical(S_IN), if nnz(S_IN) < %s || nnz(S_IN) > %s, error(''MATL:runner'', ''MATL run-time error: incorrect input specification''), end', minIn, maxIn) ... |
246 | 294 | 'else error(''MATL:runner'', ''MATL run-time error: input specification not recognized''), end' ... |
247 | | - 'if isnumeric(S_IN), nin = -S_IN+1:0; else nin = find(S_IN)-numel(S_IN); end' ... |
| 295 | + 'if isnumeric(S_IN), nin = -S_IN+1:0; else nin = find(S_IN)-numel(S_IN); end'}; |
| 296 | +newLines = [newLines implicitInputBlock]; % code block for implicit input |
| 297 | +newLines = [newLines, {... |
248 | 298 | 'in = STACK(end+nin);' ... |
249 | 299 | sprintf('if isempty(S_OUT), S_OUT = %s; end', defOut) ... |
250 | 300 | sprintf('if isnumeric(S_OUT) && numel(S_OUT) == 1, if S_OUT < %s || S_OUT > %s, error(''MATL:runner'', ''MATL run-time error: incorrect output specification''), end', minOut, maxOut) ... |
251 | 301 | sprintf('elseif islogical(S_OUT), if numel(S_OUT) < %s || numel(S_OUT) > %s, error(''MATL:runner'', ''MATL run-time error: incorrect output specification''), end', minOut, maxOut) ... |
252 | 302 | 'else error(''MATL:runner'', ''MATL run-time error: output specification not recognized''), end' ... |
253 | 303 | 'if isnumeric(S_OUT), nout = S_OUT; else nout = numel(S_OUT); end' ... |
254 | | - 'out = cell(1,nout);' }; |
| 304 | + 'out = cell(1,nout);' }]; |
255 | 305 | % For logical S_IN we use nnz (the inputs are picked from the stack), but |
256 | 306 | % for logical S_OUT we use numel (the function is called with that many outputs) |
257 | 307 | if consume |
|
0 commit comments