The Great Documentation Efort, a small refactor and small bug fixes
This commit is contained in:
parent
b4a94461a7
commit
dfdd65abdf
395
polymani.pl
395
polymani.pl
@ -46,52 +46,66 @@ polyplay :-
|
||||
prompt(OldPrompt, '> '),
|
||||
%% Read a line as codes, from the 'user_input' stream
|
||||
read_line_to_codes(user_input, InCodes),
|
||||
%% Restore old prompt
|
||||
prompt(_, OldPrompt),
|
||||
%% Split the input at spaces and ignore \r and \t
|
||||
split_string(InCodes, " ", "\r\t", LS),
|
||||
%% Convert each set of codes into a term or atom, as appropriate
|
||||
maplist(name, LA, LS),
|
||||
(
|
||||
%% If we read a 'bye', terminate
|
||||
LA == [bye],
|
||||
write("See ya"),
|
||||
nl,
|
||||
!
|
||||
;
|
||||
(
|
||||
%% Parse the input into a tree
|
||||
parse_input(TIn, LA, NC),
|
||||
(
|
||||
parse_input(TIn, LA, NC),
|
||||
(
|
||||
TIn == void,
|
||||
writeln("I didn't understand what you want."),
|
||||
writeln(NC)
|
||||
;
|
||||
(
|
||||
NC \== [],
|
||||
write("Syntax error in token: "),
|
||||
cons(H, _, NC),
|
||||
write(H),
|
||||
nl
|
||||
;
|
||||
(
|
||||
debug_print(true),
|
||||
write(LA),
|
||||
nl,
|
||||
write(TIn),
|
||||
nl
|
||||
;
|
||||
process_input(TIn)
|
||||
)
|
||||
)
|
||||
)
|
||||
%% If the tree is empty, it means nothing was understood
|
||||
TIn == void,
|
||||
writeln("I didn't understand what you want."),
|
||||
writeln(NC)
|
||||
;
|
||||
writeln("I didn't understand what you want.")
|
||||
),
|
||||
polyplay
|
||||
(
|
||||
%% If there is unconsumed input, it means there was a syntatic error
|
||||
NC \== [],
|
||||
write("Syntax error in token: "),
|
||||
%% Take the head of the list
|
||||
cons(H, _, NC),
|
||||
write(H),
|
||||
nl
|
||||
;
|
||||
(
|
||||
%% If the debug_print flag is true, print some extract debug info
|
||||
debug_print(true),
|
||||
write(LA),
|
||||
nl,
|
||||
write(TIn),
|
||||
nl
|
||||
;
|
||||
%% Otherwise, process the parse tree and execute the commands within
|
||||
process_input(TIn)
|
||||
)
|
||||
)
|
||||
)
|
||||
;
|
||||
%% Parsing failed
|
||||
writeln("I didn't understand what you want.")
|
||||
),
|
||||
!.
|
||||
%% Go back to the beginning
|
||||
polyplay
|
||||
),
|
||||
!.
|
||||
|
||||
%% Flag which determines whether to print the parsed input or to process it
|
||||
debug_print(false).
|
||||
|
||||
process_input(command(CL, void)) :-
|
||||
do_process_input(CL).
|
||||
%% process_input(+tree) is determines
|
||||
%
|
||||
% Execute the commands from the parse tree
|
||||
%
|
||||
process_input(command(CL, TCR)) :-
|
||||
%% Process first command
|
||||
do_process_input(CL),
|
||||
@ -99,98 +113,147 @@ process_input(command(CL, TCR)) :-
|
||||
TCR \== void,
|
||||
%% recurse
|
||||
process_input(TCR).
|
||||
process_input(command(CL, void)) :-
|
||||
%% Process only command left
|
||||
do_process_input(CL).
|
||||
|
||||
%% do_process_input(+tree) is det
|
||||
%
|
||||
% Process a single command from the input
|
||||
% Takes, as the only argument, the tree representing
|
||||
% the work to be done
|
||||
%
|
||||
do_process_input(show_stored_polynomials) :-
|
||||
%% If the command is 'show_stored_polynomials'
|
||||
%% Store in D the list of all results of
|
||||
%% polynomial_store, which is a dynamic predicate
|
||||
findall(nm(X,Y), polynomial_store(X,Y), D),
|
||||
%% Print the list of stored variables
|
||||
print_all_stored_variables(D).
|
||||
do_process_input(show(store(P), T)) :-
|
||||
( polynomial_store(P, _),
|
||||
retractall(polynomial_store(P, _)); true ),
|
||||
!,
|
||||
assertz(polynomial_store(P, T)),
|
||||
write(P),
|
||||
write(" = "),
|
||||
polynomial_tree_to_polynomial(T, Pl),
|
||||
write(Pl),
|
||||
nl.
|
||||
%% If the command was to store and show
|
||||
%% Delegate the work of storing
|
||||
do_process_input(store(P, T)),
|
||||
%% Show the variable and the polynomial. Delegate
|
||||
do_process_input(show(P, T)).
|
||||
do_process_input(show(load(P), void)) :-
|
||||
%% Make sure there's a variable
|
||||
P \== void,
|
||||
(
|
||||
%% Check if the variable is stored
|
||||
polynomial_store(P, T),
|
||||
write(P),
|
||||
write(" = "),
|
||||
polynomial_tree_to_polynomial(T, Pl),
|
||||
write(Pl),
|
||||
nl
|
||||
%% Show the variable and the polynomial. Delegate
|
||||
do_process_input(show(P, T))
|
||||
;
|
||||
write("Variable not stored"),
|
||||
nl
|
||||
writeln("Variable not stored")
|
||||
).
|
||||
do_process_input(show(void, T)) :-
|
||||
%% Make sure there's a tree
|
||||
T \== void,
|
||||
%% Convert it to a flat polynomial
|
||||
polynomial_tree_to_polynomial(T, Pl),
|
||||
writeln(Pl).
|
||||
do_process_input(show(P, T)) :-
|
||||
%% Make sure the arguments are in the right format and not one
|
||||
%% that should be handled by other clauses
|
||||
P \== void,
|
||||
P \== store(_),
|
||||
P \== load(_),
|
||||
T \== void,
|
||||
%% Write out the variable and the normal
|
||||
%% representation of the polynomial
|
||||
write(P),
|
||||
write(" = "),
|
||||
%% Convert the input tree to a flat polynomial, to print
|
||||
polynomial_tree_to_polynomial(T, Pl),
|
||||
write(Pl),
|
||||
nl.
|
||||
do_process_input(show(void, T)) :-
|
||||
T \== void,
|
||||
polynomial_tree_to_polynomial(T, Pl),
|
||||
write(Pl),
|
||||
nl.
|
||||
writeln(Pl).
|
||||
do_process_input(store(P, T)) :-
|
||||
(
|
||||
%% If there is a polynomial stored with the same name
|
||||
polynomial_store(P, _),
|
||||
%% Delete all occurences of it
|
||||
retractall(polynomial_store(P, _))
|
||||
;
|
||||
%% Otherwise, move forward and don't do anything special
|
||||
true
|
||||
),
|
||||
!,
|
||||
%% Dynamically add to the end of the predicate, effectively storing it
|
||||
assertz(polynomial_store(P, T)).
|
||||
do_process_input(forget(P)) :-
|
||||
retract(polynomial_store(P, _)).
|
||||
%% Remove all stored predicates with this variable
|
||||
retractall(polynomial_store(P, _)).
|
||||
do_process_input(simplify(PT)) :-
|
||||
%% Convert the polynomial to it's flat representation
|
||||
polynomial_tree_to_polynomial(PT, P),
|
||||
%% Use simpoly from the UI layer to simplify, so it
|
||||
%% gives nice error messages
|
||||
simpoly(P, SP),
|
||||
write(SP),
|
||||
nl.
|
||||
writeln(SP).
|
||||
do_process_input(multiply(TN, PT)) :-
|
||||
%% To multiply, assume the left is a number
|
||||
%% Flatten both
|
||||
polynomial_tree_to_polynomial(TN, N),
|
||||
polynomial_tree_to_polynomial(PT, P),
|
||||
%% Use function from UI layer
|
||||
scalepoly(N, P, P2),
|
||||
%% Simplify
|
||||
simpoly(P2, SP),
|
||||
write(SP),
|
||||
nl.
|
||||
|
||||
writeln(SP).
|
||||
|
||||
%% print_all_stored_variables
|
||||
%
|
||||
% Prints the stored variables
|
||||
% Prints the stored variables, given the list
|
||||
%
|
||||
print_all_stored_variables([nm(X,T) | TS]) :-
|
||||
%% Print
|
||||
write(X),
|
||||
write(" = "),
|
||||
polynomial_tree_to_polynomial(T, P),
|
||||
write(P),
|
||||
nl,
|
||||
writeln(P),
|
||||
%% Recurse on the right
|
||||
print_all_stored_variables(TS).
|
||||
print_all_stored_variables([]).
|
||||
|
||||
%% polynomial_tree_to_polynomial(+tree, -polynomial) is det
|
||||
%
|
||||
% Flatten a polynomail tree into a simple polynomial
|
||||
%
|
||||
polynomial_tree_to_polynomial(op(Op, TL, TR), P) :-
|
||||
%% If it matched on the version with a node, don't go back
|
||||
!,
|
||||
%% Recurse on the left and right
|
||||
polynomial_tree_to_polynomial(TL, PL),
|
||||
polynomial_tree_to_polynomial(TR, PR),
|
||||
%% Convert the results of the recursion to atoms
|
||||
term_to_atom(PL, TermL),
|
||||
term_to_atom(PR, TermR),
|
||||
%% Concat the parts
|
||||
atom_concat(TermL, Op, Temp),
|
||||
atom_concat(Temp, TermR, PA),
|
||||
%% Convert back to terms
|
||||
term_to_atom(P, PA).
|
||||
polynomial_tree_to_polynomial(load(P), Pl) :-
|
||||
%% If there's a load tag, don't go back
|
||||
!,
|
||||
%% Retrieve the polynomial from the store
|
||||
polynomial_store(P, TP),
|
||||
%% Recurse as if there was a normal tree here
|
||||
polynomial_tree_to_polynomial(TP, Pl).
|
||||
%% If we get here, it means we didn't match any of the previous
|
||||
%% clauses, so the tree is already flat
|
||||
polynomial_tree_to_polynomial(T, T).
|
||||
%% Tests:
|
||||
%% ?- polynomial_tree_to_polynomial(op(+, 2, op(+, 2, op(*, 1, y))), S).
|
||||
%@ S = 2+2+1*y.
|
||||
|
||||
%% nlp_number(?W:Atom, ?D:Int) is det
|
||||
%% special_word_number(?W:Atom, ?D:Int) is det
|
||||
%
|
||||
% Definition of a Alphabetical and Numerical relation
|
||||
% The third argument refers to different types of precedence:
|
||||
% - f means a single unit digit, which doesn't
|
||||
% combine on the right, but can on the left
|
||||
% - g means a number which doesn't combine left or right
|
||||
% - fy means a number which can optionally combine on the right
|
||||
% - xfy means a number which requires a number on the left and
|
||||
% an optional one on the right
|
||||
%
|
||||
special_word_number(zero, 0, f).
|
||||
special_word_number(a, 1, f).
|
||||
@ -228,58 +291,106 @@ special_word_number(million, 1000000, xfy).
|
||||
%% special_word_number(third, 0.33333, xf).
|
||||
%% special_word_number(quarter, 0.25, xf).
|
||||
|
||||
|
||||
%% nlp_number(?W:Atom, ?D:Int) is det
|
||||
%% parse_number_explicit(+precedence, +tree_left, -tree,
|
||||
%% +stream, -not_consumed) is det
|
||||
%
|
||||
% Definition of a Alphabetical and Numerical relation
|
||||
% Use the precedence of the last number and the tree
|
||||
% on the left to create the tree on the right, parsing
|
||||
% the input stream.
|
||||
%
|
||||
% You probably want to call this with void in the first
|
||||
% two arguments. They are for internal use
|
||||
%
|
||||
|
||||
%% Entry point
|
||||
parse_number_explicit(void, void, T, [WN | In], NC) :-
|
||||
%% Entry point
|
||||
%% Convert a word to a number with precedence f, g, or fy
|
||||
special_word_number(WN, N, P),
|
||||
member(P, [f, g, fy]),
|
||||
!,
|
||||
%% Recurse with the previous precedence
|
||||
%% and tree as arguments. The same in the other clauses
|
||||
parse_number_explicit(P, N, T, In, NC).
|
||||
parse_number_explicit(fy, NL, T, [WN | In], NC) :-
|
||||
%% If we read an fy before and now an f
|
||||
special_word_number(WN, N, f),
|
||||
!,
|
||||
%% Add them on the left tree and recurse
|
||||
parse_number_explicit(f, op(+, NL, N), T, In, NC).
|
||||
parse_number_explicit(xfy, TL, T, [WN | In], NC) :-
|
||||
%% Parsed an xfy before, now parse any number on the right
|
||||
TL \= void,
|
||||
special_word_number(WN, N, P),
|
||||
member(P, [f, g, fy]),
|
||||
!,
|
||||
%% Add the parts
|
||||
parse_number_explicit(P, op(+, TL, N), T, In, NC).
|
||||
parse_number_explicit(_, TL, T, [WN | In], NC) :-
|
||||
%% Whatever the precedence on the left
|
||||
special_word_number(WN, N, xfy),
|
||||
%% Enforce there was a left argument
|
||||
TL \= void,
|
||||
!,
|
||||
%% Multiply this and the left
|
||||
parse_number_explicit(xfy, op(*, TL, N), T, In, NC).
|
||||
parse_number_explicit(P, TL, T, [and, WN | In], NC) :-
|
||||
%% And is part of a valid number if there's a valid
|
||||
%% number on the left and right
|
||||
special_word_number(WN, _, _),
|
||||
%% Passthrough
|
||||
parse_number_explicit(P, TL, T, [WN | In], NC),
|
||||
!.
|
||||
parse_number_explicit(_, T, T, [WN | In], [WN | In]) :-
|
||||
%% If there's a tree
|
||||
T \= void,
|
||||
%% And can't consume more words as
|
||||
%% numbers (fail on first), then we're done
|
||||
not(special_word_number(WN, _, _)),
|
||||
!.
|
||||
parse_number_explicit(_, T, T, [], []) :-
|
||||
%% If consumed all innput and there's a
|
||||
%% tree, we're done
|
||||
T \= void,
|
||||
!.
|
||||
|
||||
parse_number(op('.', TL, TR)) -->
|
||||
parse_number_explicit(void, void, TL),
|
||||
%% parse_floating_number(-tree, +stream, -not_consumed) is det
|
||||
%
|
||||
% Parse a floating point number
|
||||
%
|
||||
parse_floating_number(op('.', TL, TR)) -->
|
||||
%% A float is a node with a dot as the operator
|
||||
%% If there's a number on the left
|
||||
parse_number(TL),
|
||||
%% Followed by either point or dot
|
||||
[X],
|
||||
{ member(X, [point, dot]), ! },
|
||||
parse_number_explicit(void, void, TR).
|
||||
%% Followed by another number
|
||||
parse_positive_number(TR).
|
||||
|
||||
%% parse_positive_number(-tree, +stream, -not_consumed) is det
|
||||
%
|
||||
% Parse an positive integer number
|
||||
%
|
||||
parse_positive_number(N) -->
|
||||
[N],
|
||||
%% CLPFD, a number between 0 and infinity
|
||||
{ N in 0..sup, ! }.
|
||||
parse_positive_number(T) -->
|
||||
parse_number_explicit(void, void, T).
|
||||
|
||||
%% parse_number(-tree, +stream, -not_consumed) is det
|
||||
%
|
||||
% Parse an integer number
|
||||
%
|
||||
parse_number(N) -->
|
||||
[N],
|
||||
{ number(N), ! }.
|
||||
%% CLPFD, a number between negative infinity and positive infinity
|
||||
{ not(atom(N)), N in inf..sup, ! }.
|
||||
parse_number(op(neg, T)) --> % TODO
|
||||
%% A number can start with negative, to negate it
|
||||
[negative],
|
||||
parse_number_explicit(void, void, T).
|
||||
parse_number(T) -->
|
||||
parse_number_explicit(void, void, T).
|
||||
%% NOTE This is not supposed to be here.
|
||||
%% polynomial_tree_to_polynomial(T1, PP),
|
||||
%% simpoly(PP, T2).
|
||||
%% Tests:
|
||||
%% ?- parse_number(T, [two], _).
|
||||
%@ T = 2.
|
||||
@ -296,7 +407,8 @@ parse_number(T) -->
|
||||
%@ false.
|
||||
%% ?- parse_number(T, [twenty, one], _).
|
||||
%@ T = op(+, 20, 1).
|
||||
%% ?- parse_number(T, [hundred], _).
|
||||
%% ?- parse_number(T, [negative, one, hundred], _).
|
||||
%@ T = op(neg, op(*, 1, 100)) ;
|
||||
%@ false.
|
||||
%% ?- parse_number(T, [three, hundred], _).
|
||||
%@ T = op(*, 3, 100).
|
||||
@ -327,7 +439,6 @@ parse_number(T) -->
|
||||
%
|
||||
% Parse powers
|
||||
%
|
||||
%% Order matters
|
||||
parse_power(op(^, TB, 2)) -->
|
||||
parse_polynomial_variable(TB),
|
||||
[squared].
|
||||
@ -337,49 +448,94 @@ parse_power(op(^, TB, 3)) -->
|
||||
parse_power(op(^, TB, TN)) -->
|
||||
parse_polynomial_variable(TB),
|
||||
[raised, to],
|
||||
parse_number(TN).
|
||||
parse_positive_number(TN).
|
||||
parse_power(TB) -->
|
||||
parse_polynomial_variable(TB).
|
||||
|
||||
|
||||
%% parse_operation(+Op, +stream, -not_consumed) is det
|
||||
%
|
||||
% Associate an operator with a word
|
||||
%
|
||||
parse_operation(+) --> [plus].
|
||||
parse_operation(*) --> [times].
|
||||
|
||||
parse_polynomial_operand(T) --> parse_number(T).
|
||||
parse_polynomial_operand(T) --> parse_power(T).
|
||||
parse_polynomial_operand(load(T)) --> parse_stored_variable(T), { ! }.
|
||||
%% parse_polynomial_operand(-tree) is det
|
||||
%
|
||||
% Parse a valid operand for either side of an
|
||||
% operation in a polynomial
|
||||
%
|
||||
parse_polynomial_operand(T) -->
|
||||
parse_floating_number(T).
|
||||
parse_polynomial_operand(T) -->
|
||||
parse_power(T).
|
||||
parse_polynomial_operand(load(T)) -->
|
||||
%% Tag the variable, to be loaded later
|
||||
parse_stored_variable(T),
|
||||
{ ! }.
|
||||
|
||||
%% Declare polynomial_store as a dynamic predicate with two arguments
|
||||
%% Used to store and retrieve polynomials associated with a variable
|
||||
:- dynamic polynomial_store/2.
|
||||
|
||||
%% parse_stored_variable(-var) is det
|
||||
%
|
||||
% Parse a valid variable name, for storage
|
||||
% A valid varaible is one that would be valid in Prolog
|
||||
%
|
||||
parse_stored_variable(P) -->
|
||||
[P],
|
||||
{
|
||||
atom_codes(P, L),
|
||||
cons(F, R, L),
|
||||
code_type(F, prolog_var_start),
|
||||
maplist(code_type_swap(prolog_identifier_continue), R)
|
||||
}.
|
||||
{ valid_store_variable(P) }.
|
||||
%% Tests:
|
||||
%% ?- parse_stored_variable(P, ['P1'], _).
|
||||
%@ P = 'P1'.
|
||||
%% ?- parse_stored_variable(P, ['x1'], _).
|
||||
%@ false.
|
||||
|
||||
%% parse_stored_variable(+var) is det
|
||||
%
|
||||
% Check if var is a valid variable name, for storage
|
||||
% A valid varaible is one that would be valid in Prolog
|
||||
%
|
||||
valid_store_variable(P) :-
|
||||
%% Get the list of codes of the atom
|
||||
atom_codes(P, L),
|
||||
%% Extract the first element
|
||||
cons(F, R, L),
|
||||
%% Partially builtin facilities:
|
||||
%% Check if it's a valid start to a Prolog variable
|
||||
code_type(F, prolog_var_start),
|
||||
%% Check that each of the following is a valid
|
||||
%% continuation to a variable name
|
||||
maplist(code_type_swap(prolog_identifier_continue), R).
|
||||
|
||||
%% code_type_swap - swap arguments of code_type, so
|
||||
%% it can be used with maplist. No lambdas...
|
||||
code_type_swap(X, Y) :- code_type(Y, X).
|
||||
|
||||
%% parse_polynomial_variable(-base, +stream, -not_consumed) is det
|
||||
%
|
||||
% Parse a polynomial variable
|
||||
%
|
||||
parse_polynomial_variable(B) -->
|
||||
[B],
|
||||
{ polynomial_variable(B) }.
|
||||
|
||||
|
||||
%% parse_polynomial(-tree, +stream, -not_consumed) is det
|
||||
%
|
||||
% Parse a polynomial. Delegates to explicit variant
|
||||
%
|
||||
parse_polynomial(T) -->
|
||||
%% Ignore "polynomail", if followed by a valid polynomial
|
||||
[polynomial],
|
||||
{ ! },
|
||||
%% Delegate
|
||||
parse_polynomial_explicit(_-_, T).
|
||||
parse_polynomial(T, NC, NC) :-
|
||||
not(parse_polynomial_explicit(_-_, T, NC, _)),
|
||||
parse_polynomial(void, NC, NC) :-
|
||||
%% If can't parse more, done here
|
||||
not(parse_polynomial_explicit(_-_, _, NC, _)),
|
||||
!.
|
||||
parse_polynomial(T) -->
|
||||
%% Delegate
|
||||
parse_polynomial_explicit(_-_, T),
|
||||
!.
|
||||
%% Tests:
|
||||
@ -395,8 +551,8 @@ parse_polynomial(T) -->
|
||||
%@ T = op(+, 2, op(*, 3, 4)).
|
||||
%% ?- parse_polynomial(T, [two, plus, three, times, four, plus, six, times, five], _).
|
||||
%@ T = op(+, 2, op(+, op(*, 3, 4), op(*, 6, 5))).
|
||||
%% ?- parse_polynomial(T, [two, times, times, two], NC), write(T).
|
||||
%@ _2986 %% NOTE Potential problem. It seems NC isn't unified with the list, if it fails
|
||||
%% ?- parse_polynomial(T, [two, times, times, two], NC).
|
||||
%@ T = void,
|
||||
%@ NC = [two, times, times, two].
|
||||
%% ?- parse_polynomial(T, [two, plus, x, times, four], _).
|
||||
%@ T = op(+, 2, op(*, x, 4)).
|
||||
@ -409,36 +565,69 @@ parse_polynomial(T) -->
|
||||
%@ T = op(+, op(+, 2, 3), op(*, 4, y)),
|
||||
%@ NC = [].
|
||||
|
||||
|
||||
%% parse_polynomial_explicit(+tree-at, -tree) is det
|
||||
%
|
||||
% Explicitly parse a polynomial. You probably don't want
|
||||
% to call this directly. The first argument is a difference
|
||||
% structure of the tree on the left; the second of the pair
|
||||
% represents where to put the rest of the tree, in
|
||||
% subsequent passes
|
||||
%
|
||||
% Call with _-_ on the first argument, outputs the
|
||||
% tree on the right
|
||||
%
|
||||
parse_polynomial_explicit(void-_, T) -->
|
||||
%% Entry point. If the three on the left is void
|
||||
%% Parse an operand and an op
|
||||
parse_polynomial_operand(TL),
|
||||
parse_operation(Op),
|
||||
%% If consumed an op, double down and don't go back
|
||||
!,
|
||||
%% Recurse with the tree on the left populated with
|
||||
%% what we found and a reference to the place to
|
||||
%% place the next tree
|
||||
parse_polynomial_explicit(op(Op, TL, TRP)-TRP, T).
|
||||
parse_polynomial_explicit(TLP-TL, T) -->
|
||||
%% Parse an operand on the left and place it in the tree
|
||||
%% on the left, through the difference structure,
|
||||
parse_polynomial_operand(TL),
|
||||
%% if we find a plus
|
||||
parse_operation(+),
|
||||
!,
|
||||
%% Recurse on the right; position the sub tree on the right
|
||||
parse_polynomial_explicit(op(+, TLP, TRP)-TRP, T).
|
||||
parse_polynomial_explicit(TLP-T, TLP) -->
|
||||
%% Parse an operand on the left, placing the result of the
|
||||
%% recusion on the TLP, through the difference structure and return that
|
||||
parse_polynomial_operand(TL),
|
||||
%% If we find a times,
|
||||
parse_operation(*),
|
||||
!,
|
||||
%% Place the operand on the left, the following on the
|
||||
%% right and get a T to place in the tree on the left from above
|
||||
parse_polynomial_explicit(op(*, TL, TRP)-TRP, T).
|
||||
parse_polynomial_explicit(TLP-T, TLP) -->
|
||||
%% Same as above, but without an operator,
|
||||
parse_polynomial_operand(TL),
|
||||
%% Assume times
|
||||
parse_polynomial_explicit(op(*, TL, TRP)-TRP, T),
|
||||
!.
|
||||
parse_polynomial_explicit(TLP-TL, TLP) -->
|
||||
{ TLP \= void },
|
||||
%% Base case. Parse a last operand
|
||||
parse_polynomial_operand(TL),
|
||||
!,
|
||||
{ TL \= void }.
|
||||
parse_polynomial_explicit(void-_, T) -->
|
||||
%% Base case. Parse a single operand
|
||||
parse_polynomial_operand(T),
|
||||
!,
|
||||
{ T \= void }.
|
||||
|
||||
%% parse_command(-tree, +stream, -not_consumed) is semidet
|
||||
%
|
||||
% Parse each individual command
|
||||
%
|
||||
parse_command(show_stored_polynomials) -->
|
||||
[show, stored, polynomials].
|
||||
parse_command(forget(P)) -->
|
||||
@ -485,16 +674,28 @@ parse_command(op(+, TN, TP)) -->
|
||||
%@ T = show(void, 3),
|
||||
%@ NC = [] .
|
||||
%% ?- parse_command(T, [add, 3, plus, x, to, 4, plus, x], NC).
|
||||
%@ false.
|
||||
%@ T = op(+, op(+, 3, x), op(+, 4, x)),
|
||||
%@ NC = [] ;
|
||||
%@ false.
|
||||
|
||||
%% parse_input(-tree) is det
|
||||
%
|
||||
% Parse each command and string it into a list
|
||||
%
|
||||
parse_input(command(TCL, TCR)) -->
|
||||
%% Result is a struct with a command on the left
|
||||
%% and a struct of commands on the right
|
||||
%% parse a single command
|
||||
parse_command(TCL),
|
||||
%% separator
|
||||
[and],
|
||||
!,
|
||||
%% Recurse
|
||||
parse_input(TCR).
|
||||
parse_input(command(TC, void)) -->
|
||||
%% If there's no separator, we're done recursing
|
||||
%% parse a single command
|
||||
parse_command(TC).
|
||||
%% ?- parse_input(CT, [show, 3], _).
|
||||
%@ CT = command(show(void, 3), void).
|
||||
|
Reference in New Issue
Block a user