Додате процедуре за прераду ниски
This commit is contained in:
parent
eaf7c19617
commit
3c05965a77
|
@ -62,6 +62,7 @@ void init()
|
|||
addSymbolInternal("дужина-ниске", &strLengthInt, 0);
|
||||
addSymbolInternal("именилац", &denominatorInt, 0);
|
||||
addSymbolInternal("конс", &consInt, 0);
|
||||
addSymbolInternal("карактер", &charInt, 0);
|
||||
addSymbolInternal("карактер?", &charQInt, 0);
|
||||
addSymbolInternal("конс?", &consQInt, 0);
|
||||
addSymbolInternal("ламбда", &lambdaInt, 1);
|
||||
|
@ -82,6 +83,7 @@ void init()
|
|||
addSymbolInternal("реалан?", &realQInt, 0);
|
||||
addSymbolInternal("тачно->нетачно", &exactToInexactInt, 0);
|
||||
addSymbolInternal("сдр", &cdrInt, 0);
|
||||
addSymbolInternal("свежи-ниске", &catInt, 0);
|
||||
addSymbolInternal("симбол?", &symbolQInt, 0);
|
||||
addSymbolInternal("читај", &readInt, 0);
|
||||
addSymbolInternal("штампај", &printInt, 0);
|
||||
|
@ -147,7 +149,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
printf("Добродошли у ЋИРИЛИСП ЧПШП окружење, верзија: " VERSION "\n");
|
||||
while (Print(Eval(Read("ШКЉ> ", stdin), globalEnv)))
|
||||
while (Print(Eval(Read("Ћ> ", stdin), globalEnv)))
|
||||
;
|
||||
printf("\nДостигнут крај улазног тока.\nЗбогом и дођите нам опет!\n");
|
||||
|
||||
|
|
79
doc/rad.tex
79
doc/rad.tex
|
@ -97,7 +97,25 @@
|
|||
Лиспова синтакса је хомоиконична, другим речима он није само способан да прерађује листе, већ је и сам његов код сачињен од листа. Ово чини саму синтаксу језика довољно једноставном да се опише једним примером позива функцијем, који у Лиспу увек бивају следећег облика: \texttt{(функција арг1 арг2 арг3 ...)}, овако изгледа готово свака операција или функција извршена у самом језику, то наравно значи да су неки, нама познати изрази као \texttt{1 / (3 + 4 * 5)}, претворени у, на први изглед, необичне \texttt{(/ 1 (+ 3 (* 4 5)))}. Међутим, управо та чудна униформност читаве синтаксе која није присутна у већини других програмских језика је управо оно што Лиспу омогућава толику изражајну моћ.
|
||||
|
||||
\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{Функције}
|
||||
Лисп није нужно функционалан језик и његове функције углавном могу да стварају ,,нуспроизводе'' над остатком програма. Међутим многи дијалекти фаворизују функционалан стил. Функције се врло често дефинишу путем ,,ламбда'' израза, који су у већини дијалеката форме:
|
||||
|
@ -134,7 +152,7 @@
|
|||
\end{verbatim}
|
||||
|
||||
\section{Кратак увод у Ћирилисп}
|
||||
Ћирилисп је минималистички, претежно функционални дијалекат Лиспа, који је дизајниран и имплементиран у сврху овог матурског рада. Његово главно дефинишуће својство јесте што за конституентне карактере токена, уместо енглеских латиничнихслова из ASCII табеле користи Уникод UTF-8 карактере који описују слова која припадају српској ћирилици.
|
||||
Ћирилисп је минималистички, претежно функционални дијалекат Лиспа, који је дизајниран и имплементиран у сврху овог матурског рада. Његово главно дефинишуће својство јесте што за конституентне карактере токена, уместо енглеских латиничних слова из ASCII табеле користи Уникод UTF-8 карактере који описују слова која припадају српској ћирилици.
|
||||
|
||||
Интерпретер који служи као имплементација овог језика се може покренути на већ постојећем фајлу или унутар ЧПШ петље, описане у под-одељку \ref{REPL}, начин на који се интерпретер може покренути на оба описана начина је објашњен у одељку Увод.
|
||||
|
||||
|
@ -194,9 +212,60 @@ Read функција (кориснику Ћирилиспа доступна к
|
|||
\end{verbatim}
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
\section{Стандардне процедуре језика}
|
||||
Већ су поменуте опиши и ламбда специјалне форме, којима се граде и везују имена за процедуре које корисник описује, међутим језик би био бескористан да не поседује сопствене, предефинисане функције за различите сврхе:
|
||||
\subsection{Стандардне процедуре језика}
|
||||
Већ су поменуте \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}
|
||||
Следе типови карактера које \texttt{read} функција распознаје:
|
||||
|
|
68
internals.c
68
internals.c
|
@ -24,6 +24,20 @@ int allNums(object list)
|
|||
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)
|
||||
/* проверава да ли је дати објекат симбол, или листа (правилна или крња), чији
|
||||
* је сваки члан симбол */
|
||||
|
@ -875,6 +889,31 @@ object makeStrInt(object parameters)
|
|||
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 result;
|
||||
|
@ -905,3 +944,32 @@ object strLengthInt(object parameters)
|
|||
|
||||
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 throwInt(object parameters);
|
||||
object makeStrInt(object parameters);
|
||||
object charInt(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':
|
||||
printf("табулар");
|
||||
break;
|
||||
case L'\0':
|
||||
printf("нул");
|
||||
default:
|
||||
printf("%lc", CHR(input));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue