Skip to content

Commit bca7a3c

Browse files
committed
Implicit input. Better compatibility with Octave. Other minor changes
1 parent 98a2184 commit bca7a3c

File tree

13 files changed

+166
-80
lines changed

13 files changed

+166
-80
lines changed

MATL_spec.pdf

4.35 KB
Binary file not shown.

funDef.mat

-13 Bytes
Binary file not shown.

funDef.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ Z! 1 1 1 1 1 1 true true out{1} = full(in{1}); convert sparse matrix to full mat
2424
X" 2 inf 3 1 1 1 true true out{1} = repmat(in{:}); replicate and tile array \matlab+repmat+
2525
Y" 2 inf 2 1 1 1 true true out{1} = repelem(in{:}); replicate elements of array \matlab+repelem+ (run-length decoding)
2626
Z" 1 1 1 1 1 1 true true out{1} = blanks(in{1}); string of blanks \matlab+blanks+
27-
# 1 1 1 0 0 0 false false S_OUT = STACK{end}; STACK(end) = []; output specification specify outputs for next function
27+
#
2828
% The numbers of inputs and outputs for # are not used by the code, but are used for generating the help file
2929
X#
30-
Y# 1 2 1 0 0 0 true true rng(in{:}); control the random number generator \matlab+rng+
30+
Y#
3131
Z# 1 3 1 0 0 0 true true data = in{1}; if ~iscell(data), data = {data}; end write to file Appends first input to file \comp{inout}, creating it if necessary. If the input is an array it is converted to char and written. If the input is a cell array input, the contents of each cell are converted to char and written, with a newline (character 10) in between. With $2$ inputs: second input specifies filename; if empty defaults to \comp{inout}. With $3$ inputs: third input specifies whether any previous contents of file should be kept.
3232
sep = char(10);
3333
if numel(in)>=2 && ~isempty(in{2}), file = in{2}; else file = 'inout'; end
@@ -38,7 +38,7 @@ Z# 1 3 1 0 0 0 true true data = in{1}; if ~iscell(data), data = {data}; end writ
3838
if n<numel(data), fwrite(fid, sep); end
3939
end
4040
fclose(fid);
41-
$ 1 1 1 0 0 0 false false S_IN = STACK{end}; STACK(end) = []; input specification specify inputs for next function
41+
$
4242
% The numbers of inputs and outputs for # are not used by the code, but are used for generating the help file
4343
X$ 1 inf 2 0 inf 1 true true [out{:}] = feval(in{:}); execute Matlab function execute Matlab function specified by first input, using the rest of the inputs as arguments.
4444
Y$ 1 2 1 1 1 1 true true out{1} = char(vpa(in{:})); variable precision arithmetic \matlab+char(vpa(...))+
@@ -309,7 +309,8 @@ YB 1 2 1 1 1 1 true true out{1} = dec2bin(in{:}); convert decimal number to bina
309309
ZB 1 1 1 1 1 1 true true out{1} = bin2dec(in{1}); convert binary string to decimal number \matlab|bin2dec|
310310
C
311311
XC 1 7 2 1 3 1 true true [out{:}] = histcounts(in{:}); histogram bin counts \matlab+histcounts+
312-
YC 2 4 2 1 1 1 true true out{1} = im2col(in{:}); rearrange array blocks into columns \matlab+im2col+
312+
YC 2 4 2 1 1 1 true true if numel(in{2})==1, if size(in{1},1)==1, in{2} = [1 in{2}]; else in{2} = [in{2} 1]; end; end rearrange array blocks into columns \matlab+im2col+. If the second input is a scalar n, it is transformed into [1 n] if the first input is a row vector, or to [n 1] otherwise
313+
out{1} = im2col(in{:});
313314
ZC
314315
D 0 inf 1 0 0 0 true true if numel(in)==1, data = in; fmt = {'%.16g '}; else data = in(1:end-1); fmt = in(end); end convert to string and display If $1$ input: \matlab+disp(num2str(..., '%.16g '))+. If several inputs: \matlab+disp(num2str(eachInput,lastInput))+, where \matlab+eachInput+ loops over all inputs but the last. In either case, (nested) cell arrays are (recursively) unboxed in linear order. \sa \matl+XD+, \matl+YD+, \matl+ZD+
315316
kk = cellfun(@iscell, data);

genHelp.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313

1414
% Statements that are not functions. Changes done here to the comment field should be
1515
% done in `matl_disp.m` too.
16+
F(end+1).source = '$';
17+
F(end).comment = 'input specification';
18+
F(end).description = 'specify inputs for next function';
19+
20+
F(end+1).source = '#';
21+
F(end).comment = 'otput specification';
22+
F(end).description = 'specify outputs for next function';
23+
1624
F(end+1).source = '"';
1725
F(end).comment = 'for';
1826
F(end).description = '\matlab+for+ (control flow: loop). \sa \matl+]+, \matl+@+, \matl+X}+, \matl+Y}+';

help.mat

164 Bytes
Binary file not shown.

matl.m

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,12 @@ function matl(varargin)
200200
end
201201

202202
% Call help, if required, and quit
203+
useTags = isMatlab && (verNum(1)>7 || (verNum(1)==7 && verNum(2)>=13));
203204
if any(options=='h')
204205
if nargin>1
205-
matl_help(H, s, verbose, isMatlab, verNum)
206+
matl_help(H, s, verbose, useTags)
206207
else
207-
matl_help(H, '', verbose, isMatlab, verNum)
208+
matl_help(H, '', verbose, useTags)
208209
end
209210
return
210211
end
@@ -214,7 +215,7 @@ function matl(varargin)
214215
if verbose
215216
disp('Parsing program')
216217
end
217-
S = matl_parse(s);
218+
S = matl_parse(s, useTags);
218219
if verbose
219220
if numel(S)~=1
220221
fprintf(' %i statements parsed\n', numel(S))
@@ -239,7 +240,7 @@ function matl(varargin)
239240
if verbose
240241
disp('Compiling program')
241242
end
242-
S = matl_compile(S, F, L, pOutFile, cOutFile, verbose, isMatlab);
243+
S = matl_compile(S, F, L, pOutFile, cOutFile, verbose, isMatlab, useTags);
243244
%if verbose
244245
% disp(' Done.')
245246
%end
@@ -253,7 +254,7 @@ function matl(varargin)
253254
%disp('--') %disp(repmat('-',size(str)))
254255
pause
255256
end
256-
matl_run(S, pOutFile, cOutFileNoExt, [], isMatlab) % ...NoExt because a file name without extension is
257+
matl_run(S, pOutFile, cOutFileNoExt, [], isMatlab, useTags) % ...NoExt because a file name without extension is
257258
% needed in old Matlab versions
258259
end
259260

@@ -263,7 +264,7 @@ function matl(varargin)
263264
disp('Press any key to run MATL program in debug mode')
264265
pause
265266
end
266-
matl_run(S, pOutFile, cOutFileNoExt, [S.compileLine], isMatlab) % ...NoExt because a file name without
267+
matl_run(S, pOutFile, cOutFileNoExt, [S.compileLine], isMatlab, useTags) % ...NoExt because a file name without
267268
% extension is needed in old Matlab versions
268269
end
269270

matl_compile.m

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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)
22
%
33
% MATL compiler. Compiles into MATLAB code.
44
% Input: struct array with parsed statements.
@@ -21,21 +21,41 @@
2121
%
2222
% Luis Mendo
2323

24-
global indStepComp
25-
global C
24+
global indStepComp C implicitInputBlock
2625

2726
indStepComp = 4;
2827

28+
if verbose
29+
disp(' Generating compiled code')
30+
end
31+
2932
Fsource = {F.source}; % this field of `F` will be used often
3033

3134
% Possible improvement: preallocate for greater speed, and modify
3235
% appendLines so that C doesn't dynamically grow
3336
C = {}; % Cell array of strings. Each cell contains a line of compiled (MATLAB) code
3437

35-
if verbose
36-
disp(' Generating compiled code')
38+
if useTags
39+
strongBegin = '<strong>';
40+
strongEnd = '</strong>';
41+
else
42+
strongBegin = '';
43+
strongEnd = '';
3744
end
3845

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+
3959
% Include function header
4060
[~, name] = fileparts(cOutFile);
4161
appendLines(['function ' name], 0)
@@ -61,6 +81,7 @@
6181
appendLines('P = pi; Y = inf; N = NaN; M = -1; G = -1j;', 0)
6282
% Constants to be used by function code
6383
appendLines('defaultInputPrompt = ''> '';', 0);
84+
appendLines('implicitInputPrompt = ''> '';', 0);
6485
% Predefine literals for functions
6586
if ~isempty(S)
6687
plf = cellstr(char(bsxfun(@plus, 'X0', [floor(0:.1:2.9).' repmat((0:9).',3,1)]))).'; % {'X0'...'Z9'}
@@ -101,8 +122,18 @@
101122
case 'literal.logicalRowArray'
102123
lit = strrep(strrep(S(n).source,'T','true,'),'F','false,');
103124
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)
105134
case 'controlFlow.for'
135+
appendLines('nin = 0;', S(n).nesting);
136+
appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input
106137
newLines{1} = sprintf('in = STACK{end}; STACK(end) = []; indFor%i = 0;', S(n).nesting);
107138
newLines{2} = sprintf('for varFor%i = in', S(n).nesting);
108139
appendLines(newLines, S(n).nesting)
@@ -117,6 +148,8 @@
117148
newLines = sprintf('indDoWhile%i = indDoWhile%i+1;', S(n).nesting, S(n).nesting);
118149
appendLines(newLines, S(n).nesting+1)
119150
case 'controlFlow.while' % 'X`'
151+
appendLines('nin = 0;', S(n).nesting);
152+
appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input
120153
newLines = { sprintf('indWhile%i = 0;', S(n).nesting) ...
121154
sprintf('condWhile%i = STACK{end};', S(n).nesting) ...
122155
'STACK(end) = [];' ...
@@ -125,19 +158,25 @@
125158
newLines = sprintf('indWhile%i = indWhile%i+1;', S(n).nesting, S(n).nesting);
126159
appendLines(newLines, S(n).nesting+1)
127160
case 'controlFlow.if' % '?'
161+
appendLines('nin = 0;', S(n).nesting);
162+
appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input
128163
newLines = { 'in = STACK{end}; STACK(end) = [];' ...
129164
'if in' };
130165
appendLines(newLines, S(n).nesting);
131166
case 'controlFlow.else' % '}'
132167
appendLines('else', S(n).nesting)
133168
case 'controlFlow.end' % ']'
134169
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
135172
newLines = { sprintf('condDoWhile%i = STACK{end};', S(n).nesting) ...
136173
'STACK(end) = [];' ...
137174
'end' ...
138175
sprintf('clear indDoWhile%i', S(n).nesting)};
139176
appendLines(newLines, S(n).nesting)
140177
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
141180
newLines = { sprintf('condWhile%i = STACK{end};', S(n).nesting) ...
142181
'STACK(end) = [];' ...
143182
'end' ...
@@ -151,11 +190,15 @@
151190
newLines = 'end';
152191
appendLines(newLines, S(n).nesting);
153192
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)
155194
end
156195
case 'controlFlow.conditionalBreak'
196+
appendLines('nin = 0;', S(n).nesting);
197+
appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input
157198
appendLines('in = STACK{end}; STACK(end) = []; if in, break, end', S(n).nesting)
158199
case 'controlFlow.conditionalContinue'
200+
appendLines('nin = 0;', S(n).nesting);
201+
appendLines(implicitInputBlock, S(n).nesting); % code block for implicit input
159202
appendLines('in = STACK{end}; STACK(end) = []; if in, continue, end', S(n).nesting)
160203
case 'controlFlow.forValue'
161204
k = S(S(n).from).nesting;
@@ -169,13 +212,17 @@
169212
case 'function'
170213
k = find(strcmp(S(n).source, Fsource), 1); % Fsource is guaranteed to contain unique entries.
171214
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
173220
end
174221
appendLines(funWrap(F(k).minIn, F(k).maxIn, F(k).defIn, F(k).minOut, F(k).maxOut, F(k).defOut, ...
175222
F(k).consumeInputs, F(k).wrap, F(k).body), S(n).nesting)
176223
C = [C strcat(blanks(indStepComp*S(n).nesting), newLines)];
177224
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)
179226
end
180227
end
181228

@@ -192,22 +239,22 @@
192239
appendLines('% Define subfunctions', 0)
193240
appendLines('', 0)
194241
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' ...
204251
'end'}, 0)
205252
% im2col
206253
appendLines('', 0)
207254
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});' ...
211258
'end'}, 0)
212259
end
213260

@@ -239,19 +286,22 @@
239286
% Code generated at the beginning of functions: check S_IN and S_OUT,
240287
% get inputs, prepare outputs, consume inputs if applicable.
241288
% `consume` indicates if inputs should be removed from the stack
289+
global implicitInputBlock
242290
newLines = { ...
243291
sprintf('if isempty(S_IN), S_IN = %s; end', defIn) ...
244292
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) ...
245293
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) ...
246294
'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, {...
248298
'in = STACK(end+nin);' ...
249299
sprintf('if isempty(S_OUT), S_OUT = %s; end', defOut) ...
250300
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) ...
251301
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) ...
252302
'else error(''MATL:runner'', ''MATL run-time error: output specification not recognized''), end' ...
253303
'if isnumeric(S_OUT), nout = S_OUT; else nout = numel(S_OUT); end' ...
254-
'out = cell(1,nout);' };
304+
'out = cell(1,nout);' }];
255305
% For logical S_IN we use nnz (the inputs are picked from the stack), but
256306
% for logical S_OUT we use numel (the function is called with that many outputs)
257307
if consume

matl_disp.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ function matl_disp(S, F, indentBase, indentStep, indentCommentSymbol, indentComm
5151
texts(ismember(Stype, {'literal.logicalRowArray'})) = {'logical row array literal'};
5252
texts(ismember(Stype, {'literal.cellArray'})) = {'cell array literal'};
5353
texts(ismember(Stype, {'literal.string'})) = {'string literal'};
54+
texts(strcmp(Stype, 'metaFunction.inSpec')) = {'input specification'};
55+
texts(strcmp(Stype, 'metaFunction.outSpec')) = {'output specification'};
5456
texts(strcmp(Stype, 'controlFlow.for')) = {'for'};
5557
texts(strcmp(Stype, 'controlFlow.doWhile')) = {'do...while'};
5658
texts(strcmp(Stype, 'controlFlow.while')) = {'while'};

0 commit comments

Comments
 (0)