Додате процедуре за прераду ниски
This commit is contained in:
parent
eaf7c19617
commit
3c05965a77
|
@ -62,6 +62,7 @@ void init()
|
||||||
addSymbolInternal("дужина-ниске", &strLengthInt, 0);
|
addSymbolInternal("дужина-ниске", &strLengthInt, 0);
|
||||||
addSymbolInternal("именилац", &denominatorInt, 0);
|
addSymbolInternal("именилац", &denominatorInt, 0);
|
||||||
addSymbolInternal("конс", &consInt, 0);
|
addSymbolInternal("конс", &consInt, 0);
|
||||||
|
addSymbolInternal("карактер", &charInt, 0);
|
||||||
addSymbolInternal("карактер?", &charQInt, 0);
|
addSymbolInternal("карактер?", &charQInt, 0);
|
||||||
addSymbolInternal("конс?", &consQInt, 0);
|
addSymbolInternal("конс?", &consQInt, 0);
|
||||||
addSymbolInternal("ламбда", &lambdaInt, 1);
|
addSymbolInternal("ламбда", &lambdaInt, 1);
|
||||||
|
@ -82,6 +83,7 @@ void init()
|
||||||
addSymbolInternal("реалан?", &realQInt, 0);
|
addSymbolInternal("реалан?", &realQInt, 0);
|
||||||
addSymbolInternal("тачно->нетачно", &exactToInexactInt, 0);
|
addSymbolInternal("тачно->нетачно", &exactToInexactInt, 0);
|
||||||
addSymbolInternal("сдр", &cdrInt, 0);
|
addSymbolInternal("сдр", &cdrInt, 0);
|
||||||
|
addSymbolInternal("свежи-ниске", &catInt, 0);
|
||||||
addSymbolInternal("симбол?", &symbolQInt, 0);
|
addSymbolInternal("симбол?", &symbolQInt, 0);
|
||||||
addSymbolInternal("читај", &readInt, 0);
|
addSymbolInternal("читај", &readInt, 0);
|
||||||
addSymbolInternal("штампај", &printInt, 0);
|
addSymbolInternal("штампај", &printInt, 0);
|
||||||
|
@ -147,7 +149,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Добродошли у ЋИРИЛИСП ЧПШП окружење, верзија: " VERSION "\n");
|
printf("Добродошли у ЋИРИЛИСП ЧПШП окружење, верзија: " VERSION "\n");
|
||||||
while (Print(Eval(Read("ШКЉ> ", stdin), globalEnv)))
|
while (Print(Eval(Read("Ћ> ", stdin), globalEnv)))
|
||||||
;
|
;
|
||||||
printf("\nДостигнут крај улазног тока.\nЗбогом и дођите нам опет!\n");
|
printf("\nДостигнут крај улазног тока.\nЗбогом и дођите нам опет!\n");
|
||||||
|
|
||||||
|
|
77
doc/rad.tex
77
doc/rad.tex
|
@ -97,7 +97,25 @@
|
||||||
Лиспова синтакса је хомоиконична, другим речима он није само способан да прерађује листе, већ је и сам његов код сачињен од листа. Ово чини саму синтаксу језика довољно једноставном да се опише једним примером позива функцијем, који у Лиспу увек бивају следећег облика: \texttt{(функција арг1 арг2 арг3 ...)}, овако изгледа готово свака операција или функција извршена у самом језику, то наравно значи да су неки, нама познати изрази као \texttt{1 / (3 + 4 * 5)}, претворени у, на први изглед, необичне \texttt{(/ 1 (+ 3 (* 4 5)))}. Међутим, управо та чудна униформност читаве синтаксе која није присутна у већини других програмских језика је управо оно што Лиспу омогућава толику изражајну моћ.
|
Лиспова синтакса је хомоиконична, другим речима он није само способан да прерађује листе, већ је и сам његов код сачињен од листа. Ово чини саму синтаксу језика довољно једноставном да се опише једним примером позива функцијем, који у Лиспу увек бивају следећег облика: \texttt{(функција арг1 арг2 арг3 ...)}, овако изгледа готово свака операција или функција извршена у самом језику, то наравно значи да су неки, нама познати изрази као \texttt{1 / (3 + 4 * 5)}, претворени у, на први изглед, необичне \texttt{(/ 1 (+ 3 (* 4 5)))}. Међутим, управо та чудна униформност читаве синтаксе која није присутна у већини других програмских језика је управо оно што Лиспу омогућава толику изражајну моћ.
|
||||||
|
|
||||||
\subsection{REPL\label{REPL}}
|
\subsection{REPL\label{REPL}}
|
||||||
Један од централних појмова у свакој имплементацији Лиспа јесте такозвани ,,Read, Evaluate, Print Loop'', у овој имплементацији познато као ЧПШП. ЧПШП је најосновнији начин интеракције са већином Лисп система, у питању је командно-линијски интерфејс у којем корисник текстуално уноси програм као низ симболичких израза, који у ,,бесконачној'' петљи учитава симболичке изразе а затим их евалуира (процењује им коначну вредност), и на крају их штампа. На пример горепоменути израз, \texttt{(/ 1 (+ 3 (* 4 5)))}, би био учитан кроз \textit{read} функцију, која би га парсирала и претворила у листу, коју би потом \textit{eval} функција проценила да има резултат \texttt{1/23} (већина имплементација природно подржава разломачку аритметику), након чега би \textit{print} штампала дати број на екрану или терминалу.
|
Један од централних појмова у свакој имплементацији Лиспа јесте такозвани ,,Read, Evaluate, Print Loop'', у овој имплементацији познато као ЧПШП. ЧПШП је најосновнији начин интеракције са већином Лисп система, у питању је командно-линијски интерфејс у којем корисник текстуално уноси програм као низ симболичких израза, који у ,,бесконачној'' петљи учитава симболичке изразе а затим их евалуира (процењује им коначну вредност), и на крају их штампа. На пример горепоменути израз:
|
||||||
|
\begin{verbatim}
|
||||||
|
(/ 1 (+ 3 (* 4 5)))
|
||||||
|
\end{verbatim}
|
||||||
|
би био учитан кроз \textit{read} функцију, која би га парсирала и претворила у листу, коју би потом \textit{eval} функција проценила да има резултат
|
||||||
|
\begin{verbatim}
|
||||||
|
1/23
|
||||||
|
\end{verbatim}
|
||||||
|
(већина имплементација природно подржава разломачку аритметику), након чега би \textit{print} штампала дати број на екрану или терминалу.
|
||||||
|
|
||||||
|
Будући да \texttt{eval} функција покушава да евалуира сваку дату непразну листу као позив на функцију која је описана првим чланом листе, а сваки симбол као референцу на неку променљиву, веома често је пожељно назначити \texttt{eval} функцији да дати израз не желимо да она евалуира, ово се у већини дијалеката чини помоћу \texttt{quote} специјалне форме. На пример уколико напишемо израз као \texttt{(1 2 3)}, највероватније желимо да на неки начин користимо листу са члановима 1, 2 и 3, а не да позовемо функцију \texttt{1} са аргументима \texttt{2} и \texttt{3}, дакле написаћемо га као:
|
||||||
|
\begin{verbatim}
|
||||||
|
(quote (1 2 3))
|
||||||
|
\end{verbatim}
|
||||||
|
Пошто се ова форма изузетно често користи чешће се виђа скраћени облик исте:
|
||||||
|
\begin{verbatim}
|
||||||
|
'(1 2 3)
|
||||||
|
'simbol
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
\subsection{Функције}
|
\subsection{Функције}
|
||||||
Лисп није нужно функционалан језик и његове функције углавном могу да стварају ,,нуспроизводе'' над остатком програма. Међутим многи дијалекти фаворизују функционалан стил. Функције се врло често дефинишу путем ,,ламбда'' израза, који су у већини дијалеката форме:
|
Лисп није нужно функционалан језик и његове функције углавном могу да стварају ,,нуспроизводе'' над остатком програма. Међутим многи дијалекти фаворизују функционалан стил. Функције се врло често дефинишу путем ,,ламбда'' израза, који су у већини дијалеката форме:
|
||||||
|
@ -194,9 +212,60 @@ Read функција (кориснику Ћирилиспа доступна к
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
\end{enumerate}
|
\end{enumerate}
|
||||||
|
|
||||||
\newpage
|
\subsection{Стандардне процедуре језика}
|
||||||
\section{Стандардне процедуре језика}
|
Већ су поменуте \texttt{опиши} и \texttt{ламбда} специјалне форме, којима се граде и везују имена за процедуре које корисник описује, међутим језик би био бескористан да не поседује сопствене, предефинисане функције за различите сврхе.
|
||||||
Већ су поменуте опиши и ламбда специјалне форме, којима се граде и везују имена за процедуре које корисник описује, међутим језик би био бескористан да не поседује сопствене, предефинисане функције за различите сврхе:
|
|
||||||
|
\subsubsection{Типови}
|
||||||
|
Неке од најбитнијих врста јесу типски предикати, другим речима функције које враћају булеан \texttt{\#и} или \texttt{\#л} у зависности од тога да ли је једини аргумент дат тип или не, језик пружа следеће предикате типова: \texttt{листа?}, \texttt{број?}, \texttt{конс?}, \texttt{нил?}, \texttt{ниска?}, \texttt{реалан?}, \texttt{разломак?}, \texttt{процедура?}, \texttt{симбол?}, \texttt{цео-број?}.
|
||||||
|
\begin{verbatim}
|
||||||
|
Ћ> (листа? 5)
|
||||||
|
#л
|
||||||
|
Ћ> (цео-број? 5)
|
||||||
|
#и
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
\subsubsection{Аритметика}
|
||||||
|
Постоји неколико функција које омогућавају извршавање рачуна над бројевима, све основне аритметичке операције су понуђене: \texttt{+}, \texttt{-}, \texttt{*}, \texttt{/}.
|
||||||
|
\begin{verbatim}
|
||||||
|
Ћ> (+ (* 3 5 4) 9)
|
||||||
|
69
|
||||||
|
Ћ> (/ (+ 6 7) (- 150 100))
|
||||||
|
13/50
|
||||||
|
Ћ> (+ (* 20 20) 20 0,666)
|
||||||
|
420,666
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
Такође постоје и функције за преобраћивање рационалног (тачног) броја, у реални (нетачни), и обратно.
|
||||||
|
\begin{verbatim}
|
||||||
|
Ћ> (тачно->нетачно 555/333)
|
||||||
|
1,666667
|
||||||
|
Ћ> (нетачно->тачно 12,250)
|
||||||
|
49/4
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
На рационалним бројевима се такође могу применити функције \texttt{бројилац} и \texttt{именилац}.
|
||||||
|
\begin{verbatim}
|
||||||
|
Ћ> (бројилац 88/14) ; разломци се скраћују, улаз је 44/7
|
||||||
|
44
|
||||||
|
Ћ> (именилац 1312) ; сваки цео број је само разломак са имениоцем 1
|
||||||
|
1
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
Коначно, постоје функције за добијање маскимума и минимума из листе бројева.
|
||||||
|
\begin{verbatim}
|
||||||
|
Ћ> (макс 3 5 2 512 3)
|
||||||
|
512
|
||||||
|
Ћ> (мин 85 99 105 110 110)
|
||||||
|
85
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
\subsubsection{Прерада листа}
|
||||||
|
Као и сваки дијалекат Лиспа, Ћирилисп поседује процедуре у сврси прераде листа и конс ћелија. \texttt{сар} (садржај адресног дела броја регистра) и \texttt{сдр} (садржај декрементног дела броја регистра) су важне процедуре за анализирање ових структура.
|
||||||
|
\begin{verbatim}
|
||||||
|
Ћ> (сар '(ČĆ))
|
||||||
|
"упркос"
|
||||||
|
\end{verbatim}
|
||||||
|
% proba.txt
|
||||||
|
|
||||||
\begin{comment}
|
\begin{comment}
|
||||||
Следе типови карактера које \texttt{read} функција распознаје:
|
Следе типови карактера које \texttt{read} функција распознаје:
|
||||||
|
|
68
internals.c
68
internals.c
|
@ -24,6 +24,20 @@ int allNums(object list)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int allStrings(object list)
|
||||||
|
{
|
||||||
|
object *currentCell = &list;
|
||||||
|
while (TYPE(*currentCell) != nilObject)
|
||||||
|
{
|
||||||
|
if (TYPE(CAR(*currentCell)) != stringObject)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
currentCell = &CDR(*currentCell);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int allSyms(object list)
|
int allSyms(object list)
|
||||||
/* проверава да ли је дати објекат симбол, или листа (правилна или крња), чији
|
/* проверава да ли је дати објекат симбол, или листа (правилна или крња), чији
|
||||||
* је сваки члан симбол */
|
* је сваки члан симбол */
|
||||||
|
@ -875,6 +889,31 @@ object makeStrInt(object parameters)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object charInt(object parameters)
|
||||||
|
{
|
||||||
|
object result;
|
||||||
|
if (listLength(parameters) != 2)
|
||||||
|
{
|
||||||
|
SIGERR(argumentNumberError);
|
||||||
|
}
|
||||||
|
if (TYPE(CAR(parameters)) != stringObject ||
|
||||||
|
TYPE(CAR(CDR(parameters))) != numberObject ||
|
||||||
|
!integer(CAR(CDR(parameters))))
|
||||||
|
{
|
||||||
|
SIGERR(typeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE(result) = charObject;
|
||||||
|
char *mbs = STR(CAR(parameters));
|
||||||
|
int index = NUM_NUMER(CAR(CDR(parameters))), current = 0;
|
||||||
|
for (current = 0; current < index && *mbs != '\0';
|
||||||
|
mbs += mblen(mbs, MB_CUR_MAX), ++current)
|
||||||
|
;
|
||||||
|
mbtowc(&CHR(result), mbs, MB_CUR_MAX);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
object strLengthInt(object parameters)
|
object strLengthInt(object parameters)
|
||||||
{
|
{
|
||||||
object result;
|
object result;
|
||||||
|
@ -905,3 +944,32 @@ object strLengthInt(object parameters)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object catInt(object parameters)
|
||||||
|
{
|
||||||
|
if (!allStrings(parameters))
|
||||||
|
{
|
||||||
|
SIGERR(typeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
object result;
|
||||||
|
TYPE(result) = stringObject;
|
||||||
|
int stringLength = 0;
|
||||||
|
object *current = ¶meters;
|
||||||
|
while (TYPE(*current) != nilObject)
|
||||||
|
{
|
||||||
|
stringLength += strlen(STR(CAR(*current)));
|
||||||
|
current = &CDR(*current);
|
||||||
|
}
|
||||||
|
STR(result) = malloc((stringLength + 1) * sizeof(char));
|
||||||
|
STR(result)[0] = '\0';
|
||||||
|
|
||||||
|
current = ¶meters;
|
||||||
|
while (TYPE(*current) != nilObject)
|
||||||
|
{
|
||||||
|
strcat(STR(result), STR(CAR(*current)));
|
||||||
|
current = &CDR(*current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -40,4 +40,6 @@ object readInt(object parameters);
|
||||||
object beginInt(object parameters);
|
object beginInt(object parameters);
|
||||||
object throwInt(object parameters);
|
object throwInt(object parameters);
|
||||||
object makeStrInt(object parameters);
|
object makeStrInt(object parameters);
|
||||||
|
object charInt(object parameters);
|
||||||
object strLengthInt(object parameters);
|
object strLengthInt(object parameters);
|
||||||
|
object catInt(object parameters);
|
||||||
|
|
2
print.c
2
print.c
|
@ -90,6 +90,8 @@ void printValue(object input)
|
||||||
case L'\t':
|
case L'\t':
|
||||||
printf("табулар");
|
printf("табулар");
|
||||||
break;
|
break;
|
||||||
|
case L'\0':
|
||||||
|
printf("нул");
|
||||||
default:
|
default:
|
||||||
printf("%lc", CHR(input));
|
printf("%lc", CHR(input));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue