diff --git a/Android/.gitignore b/Android/.gitignore index 2b75303..1d706b7 100644 --- a/Android/.gitignore +++ b/Android/.gitignore @@ -11,3 +11,4 @@ /build /captures .externalNativeBuild +app/src/main/java/io/github/ponyatov/metal/FORTH.java diff --git a/Android/FORTH.ragel b/Android/FORTH.ragel new file mode 100644 index 0000000..60952a0 --- /dev/null +++ b/Android/FORTH.ragel @@ -0,0 +1,35 @@ +package io.github.ponyatov.metal; + +//import java.text.ParseException; + +%%{ + machine lexer; + + comment = ( "#" [^\n]* ) >{ts=p;} @{EMIT(new Comment(new String(data,ts,p)));} ; + + main := ( + comment +# | any @{EMIT(new Symbol(String.valueOf(data[p])));} + )*; +}%% + +public class FORTH { + + static void EMIT(Frame c) { MainActivity.tasklist.append(c.dump()); } + +////////////////////////////////////////////////////////////////////////////////// .ragel generated + + %% write data; + + public static void parse(String cmd) /* throws ParseException */ { + + char[] data = cmd.toCharArray();// parser requires sequence storage + int cs = lexer_start; // state machine current state + int p = 0; // current parsing position + int pe = data.length; // end of source text marker + int ts = 0; // Token Start pointer + + %% write exec; + } + +} diff --git a/Android/Makefile b/Android/Makefile new file mode 100644 index 0000000..5ef43e5 --- /dev/null +++ b/Android/Makefile @@ -0,0 +1,4 @@ +SRC = app/src/main/java/ +PKG = $(SRC)/io/github/ponyatov/metal +$(PKG)/FORTH.java: FORTH.ragel Makefile + ragel -J -o $@ $< diff --git a/Android/app/build.gradle b/Android/app/build.gradle index 2c8b95a..7c43b1e 100644 --- a/Android/app/build.gradle +++ b/Android/app/build.gradle @@ -23,14 +23,7 @@ dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.android.support:design:28.0.0' - implementation 'com.google.firebase:firebase-auth:16.0.3' - testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' -// implementation 'com.google.firebase:firebase-core:16.0.8' -// implementation 'com.google.firebase:firebase-auth:16.2.0' -// implementation 'com.google.firebase:firebase-firestore:18.2.0' +// testImplementation 'junit:junit:4.12' +// androidTestImplementation 'com.android.support.test:runner:1.0.2' +// androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' } - -// required for: Firebase -apply plugin: 'com.google.gms.google-services' diff --git a/Android/app/src/main/java/io/github/ponyatov/metal/Comment.java b/Android/app/src/main/java/io/github/ponyatov/metal/Comment.java new file mode 100644 index 0000000..b1784c2 --- /dev/null +++ b/Android/app/src/main/java/io/github/ponyatov/metal/Comment.java @@ -0,0 +1,6 @@ +package io.github.ponyatov.metal; + +public class Comment extends Symbol { + final static String type = "comment"; + public Comment(String V) { super(V); } +} diff --git a/Android/app/src/main/java/io/github/ponyatov/metal/Container.java b/Android/app/src/main/java/io/github/ponyatov/metal/Container.java index f8b973e..b97e403 100644 --- a/Android/app/src/main/java/io/github/ponyatov/metal/Container.java +++ b/Android/app/src/main/java/io/github/ponyatov/metal/Container.java @@ -1,10 +1,6 @@ package io.github.ponyatov.metal; public class Container extends Frame { - - public Container(String V) { - super(V); - type = "container"; - } - + final static String type = "container"; + public Container(String V) { super(V); } } diff --git a/Android/app/src/main/java/io/github/ponyatov/metal/Dict.java b/Android/app/src/main/java/io/github/ponyatov/metal/Dict.java index e7b52eb..22a6fa5 100644 --- a/Android/app/src/main/java/io/github/ponyatov/metal/Dict.java +++ b/Android/app/src/main/java/io/github/ponyatov/metal/Dict.java @@ -1,9 +1,6 @@ package io.github.ponyatov.metal; public class Dict extends Container { - - public Dict(String V) { - super(V); - type = "dict"; - } + final static String type = "dict"; + public Dict(String V) { super(V); } } diff --git a/Android/app/src/main/java/io/github/ponyatov/metal/Frame.java b/Android/app/src/main/java/io/github/ponyatov/metal/Frame.java index 0ad8929..7129157 100644 --- a/Android/app/src/main/java/io/github/ponyatov/metal/Frame.java +++ b/Android/app/src/main/java/io/github/ponyatov/metal/Frame.java @@ -3,20 +3,35 @@ public class Frame { /// type/class tag - String type; + final static String type = "frame"; /// object value (primitive implementation language type) String value; /// construct new frame/object with given name public Frame(String V) { - type = "frame"; value = V; } /// dump in short form: header only - public String head() { - return "<" + type + ":" + value + ">"; + public String head(String prefix) { + return prefix + "<" + type + ":" + value + ">"; + } + public String head() { return head(""); } + + public String dump(int depth, String prefix) { + String S = pad(depth) + head(prefix); + return S; + } + public String dump(int depth) { return dump(depth,""); } + public String dump() { return dump(0,""); } + + String pad(int N) { + final String cr = "\n"; + final String tab = "\t"; + String S = cr; + for (int i=0;i() { - @Override - public void onComplete(@NonNull com.google.android.gms.tasks.Task task) { - if (task.isSuccessful()) msg("ok"); - if (task.isComplete()) msg("complete"); - } - }); - + FORTH.parse("# put your commands here \n" + +" 1 2.3 4e-5 0xDeadBeef 0b1101"); } @Override diff --git a/Android/app/src/main/java/io/github/ponyatov/metal/Stack.java b/Android/app/src/main/java/io/github/ponyatov/metal/Stack.java index 82d63b0..e82d2cd 100644 --- a/Android/app/src/main/java/io/github/ponyatov/metal/Stack.java +++ b/Android/app/src/main/java/io/github/ponyatov/metal/Stack.java @@ -1,9 +1,6 @@ package io.github.ponyatov.metal; public class Stack extends Container { - - public Stack(String V) { - super(V); - type = "stack"; - } + final static String type = "stack"; + public Stack(String V) { super(V); } } diff --git a/Android/app/src/main/java/io/github/ponyatov/metal/Symbol.java b/Android/app/src/main/java/io/github/ponyatov/metal/Symbol.java new file mode 100644 index 0000000..eb31e6f --- /dev/null +++ b/Android/app/src/main/java/io/github/ponyatov/metal/Symbol.java @@ -0,0 +1,6 @@ +package io.github.ponyatov.metal; + +public class Symbol extends Frame { + final static String type = "symbol"; + public Symbol(String V) { super(V); } +} diff --git a/Android/app/src/main/java/io/github/ponyatov/metal/Task.java b/Android/app/src/main/java/io/github/ponyatov/metal/Task.java index 8c59e48..dddd3a4 100644 --- a/Android/app/src/main/java/io/github/ponyatov/metal/Task.java +++ b/Android/app/src/main/java/io/github/ponyatov/metal/Task.java @@ -1,10 +1,6 @@ package io.github.ponyatov.metal; public class Task extends Frame { - - public Task(String V) { - super(V); - type = "task"; - } - + final static String type = "task"; + public Task(String V) { super(V); } } diff --git a/Android/app/src/main/java/io/github/ponyatov/metal/TaskList.java b/Android/app/src/main/java/io/github/ponyatov/metal/TaskList.java index e0c7337..09d1914 100644 --- a/Android/app/src/main/java/io/github/ponyatov/metal/TaskList.java +++ b/Android/app/src/main/java/io/github/ponyatov/metal/TaskList.java @@ -1,10 +1,6 @@ package io.github.ponyatov.metal; public class TaskList extends Vector { - - public TaskList(String V) { - super(V); - type = "tasklist"; - } - + final static String type = "tasklist"; + public TaskList(String V) { super(V); } } diff --git a/Android/app/src/main/java/io/github/ponyatov/metal/Vector.java b/Android/app/src/main/java/io/github/ponyatov/metal/Vector.java index ee3cc8f..e0288b3 100644 --- a/Android/app/src/main/java/io/github/ponyatov/metal/Vector.java +++ b/Android/app/src/main/java/io/github/ponyatov/metal/Vector.java @@ -1,9 +1,6 @@ package io.github.ponyatov.metal; public class Vector extends Container { - - public Vector(String V) { - super(V); - type = "vector"; - } + final static String type = "vector"; + public Vector(String V) { super(V); } } diff --git a/Android/app/src/main/res/mipmap-xxxhdpi/add_circle.png b/Android/app/src/main/res/mipmap-xxxhdpi/add_circle.png deleted file mode 100644 index eb5efc4..0000000 Binary files a/Android/app/src/main/res/mipmap-xxxhdpi/add_circle.png and /dev/null differ diff --git a/Makefile b/Makefile index a6fa90e..c72542e 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,8 @@ TODAY = $(shell date +%d%m%y) all: $(MAKE) -C book + $(MAKE) -C Android + $(MAKE) -C game pdf: $(MODULE)_$(TODAY).pdf $(MODULE)_$(TODAY).pdf: book/$(MODULE).pdf diff --git a/README.md b/README.md index 09b15ac..92adf78 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # metaL -## homoiconic programming language bootstrap in Python +## homoiconic metaprogramming language bootstrap in Python (c) Dmitry Ponyatov <> CC BY-NC-ND diff --git a/book/Makefile b/book/Makefile index 578e805..1831e23 100644 --- a/book/Makefile +++ b/book/Makefile @@ -4,10 +4,12 @@ TEX += intro/intro.tex intro/denial.tex intro/meta.tex TEX += intro/brooks.tex intro/lop.tex intro/homoiconic.tex TEX += first/steps.tex first/eds.tex first/whitebox.tex first/install.tex +TEX += first/run.tex first/minsky.tex first/forth.tex first/concept.tex TEX += frames/frames.tex frames/frame.tex frames/dump.tex TEX += frames/prim.tex frames/string.tex frames/symbol.tex frames/number.tex TEX += frames/container.tex frames/stack.tex frames/dict.tex +TEX += frames/active.tex TEX += forth/forth.tex forth/dict.tex forth/ply.tex forth/repl.tex TEX += forth/cmdline.tex @@ -32,11 +34,18 @@ TEX += cpp/cpp.tex cpp/gc.tex TEX += prolog/prolog.tex TEX += syntax/syntax.tex syntax/ragel/ragel.tex syntax/ragel/java.tex +LST += syntax/ragel/java??.* +TEX += syntax/ply/ply.tex +LST += syntax/ply/lex.py syntax/ply/yacc.py TEX += meta/circ.tex LST += meta/ebldfiles.ini meta/eclfiles.ini meta/files.ini LST += meta/header.ini meta/vimfiles.ini +TEX += meta/ouro/boros.tex meta/ouro/files.tex meta/ouro/info.tex +FIG += meta/ouro/boros.png +LST += meta/ouro/info.ml + TEX += mcu/mcu.tex mcu/ardu/ino.tex mcu/msp/msp.tex TEX += mcu/arm/cortex.tex mcu/arm/setup.tex @@ -54,16 +63,29 @@ TEX += code/in.tex code/emcin.tex code/cpp.tex code/ide.tex code/literate.tex TEX += concept/concept.tex TEX += gui/wx.tex +LST += gui/wx00.py gui/wx01.py gui/wx02.py +LST += gui/wx03.py gui/wx04.py gui/wx05.py gui/wx06.py +LST += gui/wx07.py gui/wx08.py gui/wx09.py gui/wx10.py +LST += gui/wx11.py gui/wx12.py gui/wx13.py gui/wx14.py +LST += gui/wx15.py gui/wx16.py gui/wx17.py gui/wx18.py +FIG += gui/wx00.png gui/wx01.png gui/wx02.png TEX += os/os.tex os/boot.tex os/sched.tex os/files.tex TEX += os/net.tex os/user.tex os/gui.tex -TEX += game/dev.tex +TEX += game/dev.tex game/cross.tex game/boot.tex game/video.tex +LST += game/cross0.mk game/boot00.mk game/boot00.objdump +TEX += game/debug.tex +LST += game/debug0.mk game/debug1.mk +FIG += game/debug1A.png game/debug1B.png game/debug1C.png /tmp/debug.pdf FIG += mcu/ardu/micro.png mcu/ardu/uno.jpg mcu/ardu/nano.jpg TEX += android/android.tex +TEX += py/py.tex +LST += py/hello*.py + TEX += docu/ment.tex TEX += bib/bib.tex @@ -79,5 +101,5 @@ LATEX = pdflatex -halt-on-error metaL.pdf: $(TEX) $(LST) $(FIG) $(LATEX) $< && $(LATEX) $< -/tmp/gnugcc.pdf: mcu/gnugcc.dot +/tmp/%.pdf: mcu/%.dot dot -T pdf -o /tmp/crop.pdf $< && pdfcrop /tmp/crop.pdf $@ diff --git a/book/bib/baranov.png b/book/bib/baranov.png new file mode 100644 index 0000000..eb787a4 Binary files /dev/null and b/book/bib/baranov.png differ diff --git a/book/bib/bib.tex b/book/bib/bib.tex index 88bcc3f..00eed6c 100644 --- a/book/bib/bib.tex +++ b/book/bib/bib.tex @@ -53,6 +53,33 @@ И.В.Романовского.\\ \url{http://www.nncron.ru/download/sf.pdf} +\clearpage +\bibitem{thinking}\ \bibfig{bib/thinking.jpg}\\ +\textbf{Способ мышления\ --- ФОРТ}\\ +Лео Броуди \\ +\href{http://www.forth.org.ru/~cactus/files/brodie.rar}{OCR/перевод}\\ +\url{http://thinking-forth.sourceforge.net/} + +\clearpage +\bibitem{kelly}\ \bibfig{bib/kelly.jpg}\\ +\textbf{Язык программирования ФОРТ}\\ +М.Келли, Н.Спайс\\ +Москва, ``Радио и связь'', 1993\\ +\href{http://www.forth.org.ru/~cactus/files/kelly.rar}{OCR/перевод} + +\clearpage +\bibitem{baranov}\ \bibfig{bib/baranov.png}\\ +\textbf{Язык Форт и его реализации}\\ +С.Н. Баранов, Н.Р. Ноздрунов\\ +``Машиностроение" Ленинградское отделение, 1988\\ +\href{http://www.forth.org.ru/~cactus/files/baranov2.rar}{OCR/перевод} + +\clearpage +\bibitem{threaded}\ \bibfig{bib/threaded.jpg}\\ +\textbf{Threaded Interpretive Languages: Their Design and Implementation}\\ +R. G. Loeliger\\ +\href{http://sinclairql.speccy.org/archivo/docs/books/Threaded_interpretive_languages.pdf}{PDF} + \clearpage \bibitem{wikicc}\ \bibfig{bib/wikicc.png}\\ \textbf{Book: Compiler Construction}\\ diff --git a/book/bib/kelly.jpg b/book/bib/kelly.jpg new file mode 100644 index 0000000..3050e4f Binary files /dev/null and b/book/bib/kelly.jpg differ diff --git a/book/bib/thinking.jpg b/book/bib/thinking.jpg new file mode 100644 index 0000000..00294ba Binary files /dev/null and b/book/bib/thinking.jpg differ diff --git a/book/bib/threaded.jpg b/book/bib/threaded.jpg new file mode 100644 index 0000000..f17965a Binary files /dev/null and b/book/bib/threaded.jpg differ diff --git a/book/first/concept.tex b/book/first/concept.tex new file mode 100644 index 0000000..79e6f03 --- /dev/null +++ b/book/first/concept.tex @@ -0,0 +1,58 @@ +\clearpage +\secrel{Концепт vs модель}\label{concept} + +\metal\ --- язык не только мета-, но и \term{концептуального программирования}. +\term{Концепт}\ это \emph{не полностью определенная} модель. Например, указав + +\begin{lstlisting} +module: hello +\end{lstlisting} +\noindent +мы сужаем множество всех возможных программ до одного программного модуля. + +\begin{lstlisting} +function: main << ( добавить в module:hello ) +\end{lstlisting} +\noindent +накладывает ограничение на то что целевая программа будет на \emc/\cpp. + +\medskip +В mainstream языках программирования мы досконально описываем каждый элемент +процесса, пошагово, точно прописываем все свойства объектов и структуру +программы. При программировании на \metal\ мы постепенно \emph{накладываем +ограничения}, сужая все множество возможных программ с помощью условий. +При этом чем больше и больше ограничений мы применям, тем ближе концепт +программы становится ее моделью: +\begin{description} +\item[модель] точное поэлементное описание системы с указанием всех +взаимосвязей между объектами. +\item[концепт] более широкое понятие так как он преднамеренно \emph{описывает +систему только частично}, указывая что у объекта \emph{может быть} такое-то +свойство, есть такой-то класс с некоторыми методами (но при этом не +декларируются \emph{все методы}). +\end{description} + +\noindent +Для реализации \term{концептуального программирования} \cite{tyugu} необходима +\term{база знаний} в которой задаются +\begin{itemize} + \item +\emph{наборы ограничений}, которые мы называем \term{концептами}, +\item +\emph{куски кода}\ --- \term{сниппеты}, которые добавляются в результирующий +код при срабатывании правил и ограничений, причем эти куски \emph{заданы +параметрически} и частично изменяются при использовании + \item +предыдущие проекты, заданные как наборы ограничений\ --- вы можете +\term{наследовать} их целиком или частями +\item +\emph{правила логического вывода} которые осуществляют синтез кода по сети +ограничений +\item +\term{скрипты}\ --- \term{императивные} процедуры, выполняемые внутри базы +знаний, для ее анализа или трансформации +\item +\term{демоны}\ --- скрипты, выполнемые в фоновом режиме: оптимизации, сборка +мусора, JIT- и фоновая компиляция скриптов и вычислительных функций в машинный +код +\end{itemize} diff --git a/book/first/eds.tex b/book/first/eds.tex index cc8b13c..494e0b8 100644 --- a/book/first/eds.tex +++ b/book/first/eds.tex @@ -7,7 +7,7 @@ исполнения, в большинстве случаев строятся по методике, которую можно назвать \term{исполняемые структуры данных}\note{EDS\ --- Executable Data Structure}. -\begin{description} +\begin{description}[nosep] \item[интерпретатор структур данных] рассматривает их как некоторое представление программ, которые можно исполнять в выбранной модели: конечный автомат, императивная программа, декларативное описание состава системы, функций diff --git a/book/first/forth.tex b/book/first/forth.tex new file mode 100644 index 0000000..8e6a88c --- /dev/null +++ b/book/first/forth.tex @@ -0,0 +1,83 @@ +\clearpage +\secrel{Язык \metal: исправленный \F}\secdown + +Хотя мы стараемся уйти от использования языка программирования как основного +средства разработки \ref{nolang}, в любом случае нам нужен способ ввода данных и +систему, и управления вычислениями. + +\emph{\metal\ не является языком +программирования}, это \term{командный язык} с помощью которого выполняется +\begin{itemize}[nosep] + \item +создание фреймов, + \item +модификация \term{фреймовой базы знаний}, + \item +запуск/останов скриптов и демонов. +\end{itemize} + +\medskip\noindent +Однако простое \term{императивное программирование} может выполняться и на +\metal, так как этот язык позволяет определять новые \F-\term{слова}, и +поддерживает \term{конкатенативное программирование} через разделяемый стек. + +\clearpage +В качестве прототипа для \metal\ был выбран язык \emph{\F: это самый +элементарный язык программирования}, который вы только можете найти. Вы можете +самостоятельно написать свой \F\ за пару вечеров или пару недель на любом языке +программирования, и для любого типа компьютера.\note{Современному +профессиональному разработчику, особенно фрилансеру, каждые 3-5 лет приходится +изучать очередной модный язык программирования, или фреймворк. Неплохим учебным +упражнением может стать реализация но новом для вас языке минимального \F, или +лучше \metal\ --- он совместим с объектной моделью современных языков +программирования, не потребует симуляции образа памяти с побайтным доступом, +и неплох в качестве простого \term{cкриптового движка}.} + +% \smallskip\noindent +\F\ был создан в 70х годах Чаком Муром для управления оборудованием +(радиотелескопом), и \emph{\F\ до сих пор великолепен в роли командной оболочки} +(CLI) для подобных задач. В том числе \F\ очень хорошо подходит как командная +консоль для микроконтроллеров с очень небольшими объемами ОЗУ порядка 8-20 +Кило(!)байт. + +\noindent +Но в роли основного языка программирования классический \F\ плох: +\begin{description}[nosep] +\item[низкоуровневая модель ВМ языка]: \F\ по факту является ассемблером +\term{виртуальной стековой машины}, и как с любым ассемблером вам приходится +самостоятельно выписывать все фишки, которые в mainstream языках доступны из +коробки. Как пример, в стандартное ядро \F\ не входит поддержка вычислений с +плавающей точкой, и полностью отсутствуют средства динамического выделения +памяти. +\item[прямой доступ к памяти по адресам]\ делает код на \F е крайне +нестабильным: ошибки в адресации тут же приводят к перезаписи данных и кода по +случайным адресам. В результате при программировании на \F\ нужно работать с +памятью на порядок аккуратнее, чем на \emc. +\end{description} + +\noindent +Из-за этих проблем было решено полностью отказаться от использования +классического \F а, оставив от него в новом языке \metal\ кое-какие фишки типа +синтаксиса, стака данных, словаря, и постфиксной нотации. + +\clearpage +Перед тем как приступать к работе с \metal, сначала следует немного поиграть с +классическим \F ом используя несколько книжек, и какую-нибудь реализацию \F\ для +вашего компьютера. Как вариант, вы можете попробовать GNU Forth для Android, или +декстопа: \url{http://gforth.org/} + +\begin{framed}\noindent +читайте эти книги очень аккуратно, желательно в перчатках и защитных очках, +иначе заразитесь и станете хроническим фортёром +\end{framed} + +\begin{itemize}[nosep] + \item Броуди \cite{starting}, и \cite{thinking} если хотите копнуть идеологию + разработки на \F\ поглубже + \item Келли, Спайс \cite{kelly} немного путано, но доставляет + \item Баранов, Ноздрунов \cite{baranov} книжка с качеством ниже среднего, но + это единственная книга на русском языке \emph{по реализации} \F + \item Threaded Languages \cite{threaded} намного глубже, но на английском +\end{itemize} + +\secup diff --git a/book/first/install.tex b/book/first/install.tex index 51334e4..42a43d9 100644 --- a/book/first/install.tex +++ b/book/first/install.tex @@ -22,3 +22,15 @@ ~$ sudo pip install flask wtforms \end{verbatim} +\clearpage +Если вы не хотите тащить большую систему, и вас интересует только базовый язык +\metal, можно установить проект Ouroboros \ref{ouro}:\ \note{из-за его +минималистичности установку можно свести к ручной загрузке всего нескольких +файлов с GitHub} + +\begin{verbatim} +$ git clone -o gh https://github.com/ponyatov/Ouroboros +\end{verbatim} + +Для использования под \win\ удобен редактор \vim:\\ +\url{https://www.vim.org/download.php} diff --git a/book/first/minsky.tex b/book/first/minsky.tex new file mode 100644 index 0000000..1797f90 --- /dev/null +++ b/book/first/minsky.tex @@ -0,0 +1,46 @@ +\secrel{Фреймы Мински}\label{minsky} + +\begin{framed}\noindent\label{nolang} +\emph{\metal\ не рассматривает язык программирования как основной метод +разработки}: задача программиста\ --- строить \term{модели} решаемых задач в +памяти системы, формируя базу знаний с использованием \term{фреймов} Мински +\cite{minsky} для представления знаний. +\end{framed} + +\term{Фрейм}\ в оригинальной формулировке понятия\ --- способ +\emph{структурного} \term{представления знаний} в искуственном интеллекте, +введенный Марвином Мински для описания струтуры знаний для восприятия +пространственных сцен \cite{minsky}. В той же книге это понятие было расширено +до универсальной структуры данных, очень близкой к понятию объекта в ООП. + +\clearpage\noindent +Фреймы имеют именованные слоты (поля объекта), которые могут хранить +\begin{description} +\item[примитивные значения] (строки, числа)\note{в ИИ рассматриваются как +значения по умолчанию при описании ситуации} +\item[ссылки] на другие фреймы +\item[активные слоты] (методы объекта) содержат исполняемые процедуры, +запускаемые по внешним или внутренним событиям +\item[пустые слоты] не имеют заданного значения, и заполняются в процессе +логического вывода или работы процедур +\end{description} + +\medskip\noindent +Наличие исполняемых элементов превращает фреймовую модель\note{в общем случае\ +--- любую структуру данных, см \ref{esd}} в \emph{модель вычислительную}, и +\term{парадигму программирования}, совмещающую в себе декларативное, +императивное, объектно-ориентированное и логическое программирование. Именно эта +универсальнось определила выбор фреймовой модели для \metal, как наиболее +подходящей для описания структур и процессов, специфичных для программного +обеспечения, и аппаратно-программных комплексов (embedded, \term{встраиваемые +системы}). + +\vspace{7mm} +Фрейм Мински был адаптирован для представления исходного кода программ и +описания данных на любых языках (программирования). Для этого во фрейм была +добавлена возможность хранения элементов \emph{в упорядоченном виде}, что +автоматически делает \term{фреймовые сети} представлением \term{атрибутных +грамматик}. Также были добавлены дополнительные поля: + +\lst{frames/frame.py}{language=Python} +\clearpage diff --git a/book/first/run.tex b/book/first/run.tex new file mode 100644 index 0000000..326109e --- /dev/null +++ b/book/first/run.tex @@ -0,0 +1,17 @@ +\clearpage +\secrel{Первый запуск} + +\begin{verbatim} +~/ouroboros $ python py.py + +ok> _ +\end{verbatim} + +\noindent +Основная реализация с веб-интерфейсом на \url{http://127.0.0.1:8888/}: + +\medskip +\fig{first/webrun.png}{height=.5\textheight} + +\clearpage +\fig{first/webrowser.png}{height=\textheight} diff --git a/book/first/steps.tex b/book/first/steps.tex index 504378f..caccb1f 100644 --- a/book/first/steps.tex +++ b/book/first/steps.tex @@ -99,5 +99,9 @@ \input{first/eds} \input{first/whitebox} \input{first/install} +\input{first/run} +\input{first/minsky} +\input{first/concept} +\input{first/forth} \secup diff --git a/book/first/webrowser.png b/book/first/webrowser.png new file mode 100644 index 0000000..c00e6b4 Binary files /dev/null and b/book/first/webrowser.png differ diff --git a/book/first/webrun.png b/book/first/webrun.png new file mode 100644 index 0000000..842a791 Binary files /dev/null and b/book/first/webrun.png differ diff --git a/book/forth/dict.tex b/book/forth/dict.tex index c4b1942..26675ce 100644 --- a/book/forth/dict.tex +++ b/book/forth/dict.tex @@ -8,7 +8,7 @@ \begin{description} \item[{dict[slot]=function}] создает словарную статью с произвольным именем \item[dict << function] создает словарную статью используя имя функции -\item[VM(function)] обертывает функцию во фрейм \ref{vm} +\item[CMD(function)] обертывает функцию во фрейм \ref{cmd} \end{description} \medskip diff --git a/book/forth/ply.tex b/book/forth/ply.tex index beb91f9..bbd4362 100644 --- a/book/forth/ply.tex +++ b/book/forth/ply.tex @@ -1,12 +1,12 @@ \secrel{Парсер с использованием библиотеки PLY}\label{ply} -Библиотека PLY позволяет писать \term{парсеры} для достаточно сложных языков. -Несмотря на то что диалекты \F/\pyf\ требуют только реализацию \term{лексера}, -есть смысл немного сэкономить усилия, и не заморачиваться с написанием -традиционного посимвольного разбора ``до пробела''. Если вам для какой-то задачи -потребуется применение \term{инфиксного синтаксиса}, типа разбора арифметических -выражений, вы сможете без особых усилий добавить для них \term{синтаксический -анализатор}. +Библиотека \file{PLY} \ref{ply}\ позволяет писать \term{парсеры} для достаточно +сложных языков. Несмотря на то что диалекты \F/\pyf\ требуют только реализацию +\term{лексера}, есть смысл немного сэкономить усилия, и не заморачиваться с +написанием традиционного посимвольного разбора ``до пробела''. Если вам для +какой-то задачи потребуется применение \term{инфиксного синтаксиса}, типа +разбора арифметических выражений, вы сможете без особых усилий добавить для них +\term{синтаксический анализатор}. Еще одно достоинство использования PLY: с ее помощью мы можем автоматически определять тип для каждой лексемы, в частности разпознавать примитивные типы @@ -14,6 +14,8 @@ особая сноска по этому поводу: для совместимости с PLY были специально выбраны имена переменных типа и значения: \verb|type| и \verb|value|. +Подробное использование библиотеки \file{PLY} см. \ref{ply}. + \clearpage \lst{forth/parser.py}{language=Python} @@ -29,19 +31,5 @@ \item[t\_error()] обработка синтаксических ошибок: нераспознанные символы \end{description} -\clearpage -\noindent -Каждое правило лексера задается в виде функции, её docstring задает регулярное -выражение, которому должна удовлетворять группа символов, чтобы быть -распознанной. Функция получает на вход параметр \verb|t| содержащий -\textit{состояние лексера}; \verb|t.value| содержит распознанную группу символов -в виде строки, которую мы возвращаем из функции через вызов конструктора фрейма -соответствующего типа. - -\bigskip -\noindent -\verb|ply.lex.lex()| проходит по исходному коду текущего модуля \py, находит -функции соответствующие шаблону правил лексера, и синтезирует функцию-лексер. - -\medskip +% \medskip \lst{forth/lexer.py}{language=Python} diff --git a/book/forth/repl.tex b/book/forth/repl.tex index 49a5987..3e537d5 100644 --- a/book/forth/repl.tex +++ b/book/forth/repl.tex @@ -1,3 +1,4 @@ +\clearpage \secrel{Интерпретатор} \lst{forth/repl.py}{language=Python} diff --git a/book/frames/active.py b/book/frames/active.py new file mode 100644 index 0000000..d0186bb --- /dev/null +++ b/book/frames/active.py @@ -0,0 +1 @@ +class Active(Frame): pass diff --git a/book/frames/active.tex b/book/frames/active.tex new file mode 100644 index 0000000..0dcb63b --- /dev/null +++ b/book/frames/active.tex @@ -0,0 +1,41 @@ +\clearpage +\secrel{\class{Active}: исполняемые объекты}\secdown + +\lst{frames/active.py}{language=Python} + +\medskip\noindent +Очень важным подклассом фреймов являются \term{исполняемые объекты}. Именно они +превращают граф фреймов из пассивного описания объектов и их отношений в +\emph{выполняемую программу}, и придают фреймовой системе свойства +\term{гомоиконичного языка программирования}. + +\clearpage +\secrel{\class{CMD}: команда виртуальной машины}\label{cmd} + +\lst{frames/cmd.py}{language=Python} + +\medskip\noindent +Команда обертывает функцию написанную на \py\ во фрейм, отображая ее в +пространство имен \metal. + +\clearpage +\secrel{\class{VM}: виртуальная \F-машина}\label{vm}\label{FVM} + +\lst{frames/vm.py}{language=Python} + +\medskip\noindent +Фрейм виртуальной машины описывает сущность, соответствующую абстрактному +компьютеру: он имеет память программ и память данных\note{в общем случае в одном +адресном пространстве}, и стек. \class{FVM}\ является частным случаем \F-машины +\ref{forth} + +\secrel{\class{Context}: контекст}\label{context} + +\lst{frames/context.py}{language=Python} + +\medskip\noindent +Контекст\ --- текущее состояние вычисления, которое также можно рассматривать +как нить или процесс операционной системы: состояние стека, памяти, и регистров +виртуальной машины \ref{vm}. + +\secup diff --git a/book/frames/cmd.py b/book/frames/cmd.py new file mode 100644 index 0000000..49231dd --- /dev/null +++ b/book/frames/cmd.py @@ -0,0 +1,6 @@ +class CMD(Active): + def __init__(self,F): + Active.__init__(self,F.__name__) + self.fn = F + def execute(self): + self.fn() \ No newline at end of file diff --git a/book/frames/context.py b/book/frames/context.py new file mode 100644 index 0000000..c2b773b --- /dev/null +++ b/book/frames/context.py @@ -0,0 +1 @@ +class Context(Active): pass diff --git a/book/frames/dict.py b/book/frames/dict.py index 0675e4f..2126c98 100644 --- a/book/frames/dict.py +++ b/book/frames/dict.py @@ -4,12 +4,12 @@ class Dict(Container): def __setitem__(self,slot,obj): # if function? if callable(obj): - self[slot] = VM(obj) ; return self + self[slot] = CMD(obj) ; return self else: return Container.__setitem__(self, slot, obj) # operator dict << obj def __lshift__(self,obj): # if function? if callable(obj): - self << VM(obj) ; return self + self << CMD(obj) ; return self else: return Container.__lshift__(self, obj) \ No newline at end of file diff --git a/book/frames/frame.py b/book/frames/frame.py index a5e64cc..35b3e8f 100644 --- a/book/frames/frame.py +++ b/book/frames/frame.py @@ -1,14 +1,15 @@ -# extended frame model [Marvin Minsky] +# расширенная фреймовая модель [Marvin Minsky] class Frame: - # construct frame with given name + # конструктор фрейма с заданным именем def __init__(self,V): - # class/type tag (string for simplicity) + # метка класса или типа, для упрощения - строка self.type = self.__class__.__name__.lower() - # atomic value (Python primitive type) + # атомарное значение фрейма: примитивный тип Python + # хранит имя фрейма, или строку, число,.. self.value = V - # slots/attributes /associative array/ + # слоты = атрибуты : ассоциативный массив self.attr = {} - # nested objects /ordered list = stack/ + # вложенные объекты : упорядоченный список = стек self.nest = [] print Frame('hello') diff --git a/book/frames/frames.tex b/book/frames/frames.tex index cad260e..f77275c 100644 --- a/book/frames/frames.tex +++ b/book/frames/frames.tex @@ -19,4 +19,6 @@ \input{frames/container} +\input{frames/active} + \secup diff --git a/book/frames/vm.py b/book/frames/vm.py new file mode 100644 index 0000000..7a168a0 --- /dev/null +++ b/book/frames/vm.py @@ -0,0 +1,2 @@ +class VM(Active): pass +class FVM(VM): pass diff --git a/book/game/boot.tex b/book/game/boot.tex new file mode 100644 index 0000000..8d4b686 --- /dev/null +++ b/book/game/boot.tex @@ -0,0 +1,42 @@ +\clearpage +\secrel{Загрузчик Multiboot}\label{multiboot} + +Спецификация \term{Multboot} описывает интерфейс между ядром операционной +системы и загрузчиком, следуя которому любой загрузчик может применяться +универсально для загрузки любых операционных систем, если ядра этих ОС +поддерживают спецификацию Multiboot. + +Использование multiboot позволит сразу исключить лишний этап при написании своей +ОС для i386: создание загрузчика со всеми хождениями по граблям с чтением с +устройств, переключением в защищенный режим, инициализацией оборудования и т.п. +\file{QEMU} поддерживает спецификацию multiboot и может загружать ядро ОС +напрямую из файла через параметр \verb|-kernel| без образов дисков и сборки +файловых систем для эмулятора. На реальном железе вы можете использовать любой +другой загрузчик, типа \file{syslinux} \ref{syslinux} или \file{GRUB}. + +\clearpage +Чтобы скомпилировать ядро ОС, в бинарном файле в самом начале должна находиться +структура: +\bigskip + +\noindent +\url{https://habr.com/ru/post/351568/} + +\noindent +\url{https://web.archive.org/web/20070210091856/http://www.osdcom.info/content/view/33/39/} + +\bigskip + +\noindent +\begin{tabular}{l l l} +магическое число & u32 & 0xE85250D6 \\ +архитектура & u32 & 0 для i386, 4 для MIPS \\ +длина заголовка & u32 & общий размер заголовка включая тэги \\ +контрольная сумма & u32 & -(магическое число + архитектура + длина заголовка) \\ +тэги & \ldots & \\ +завершающий тэг & & (u16, u16, u32) = (0, 0, 8) \\ +\end{tabular} + +\clearpage +\lst{game/boot00.mk}{title=\file{game/Makefile}} +\lst{game/boot00.objdump}{} diff --git a/book/game/boot00.mk b/book/game/boot00.mk new file mode 100644 index 0000000..2b04ae0 --- /dev/null +++ b/book/game/boot00.mk @@ -0,0 +1,7 @@ +GCC = gcc +CFLAGS = -march=i386 -mtune=i386 -m32 -I$(CURDIR) + +multiboot.o: multiboot.S multiboot.h Makefile + $(GCC) $(CFLAGS) -c -o $@ $< &&\ + objdump -x $@ > $@.objdump + \ No newline at end of file diff --git a/book/game/boot00.objdump b/book/game/boot00.objdump new file mode 100644 index 0000000..18c0b4d --- /dev/null +++ b/book/game/boot00.objdump @@ -0,0 +1,24 @@ +multiboot.o: file format elf32-i386 +multiboot.o +architecture: i386, flags 0x00000011: +HAS_RELOC, HAS_SYMS +start address 0x00000000 + +Sections: +Idx Name Size VMA LMA File off Algn + 0 .text 00000005 00000000 00000000 00000034 2**0 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 1 .data 00000000 00000000 00000000 00000039 2**0 + CONTENTS, ALLOC, LOAD, DATA + 2 .bss 00000000 00000000 00000000 00000039 2**0 + ALLOC +SYMBOL TABLE: +00000000 l d .text 00000000 .text +00000000 l d .data 00000000 .data +00000000 l d .bss 00000000 .bss +00000000 *UND* 00000000 _start + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +00000001 R_386_PC32 _start diff --git a/book/game/cross.tex b/book/game/cross.tex new file mode 100644 index 0000000..28ff9f0 --- /dev/null +++ b/book/game/cross.tex @@ -0,0 +1,7 @@ +\secrel{Сборка кросс-компилятора для QEMU-i386}\label{cross386} + +Для компиляции игр для платформы i386 мы можем использовать штатный \term{GNU +toolchain} для \file{x86\_64}, но воспользуемся скриптом сборки +\term{кросс-компилятора} из раздела \ref{mcu}: + +\lst{game/cross0.mk}{title=\file{/game/Makefile},language=make} \ No newline at end of file diff --git a/book/game/cross0.mk b/book/game/cross0.mk new file mode 100644 index 0000000..ea8b125 --- /dev/null +++ b/book/game/cross0.mk @@ -0,0 +1,8 @@ +CPU = i386 +TARGET = $(CPU)-elf +CFG_CPU = --with-cpu=$(CPU) +CROSS = $(CURDIR)/$(TARGET)/bin + +cross: ../mcu/Makefile + make -f $< \ + TARGET=$(TARGET) CFG_CPU="$(CFG_CPU)" cross0 \ No newline at end of file diff --git a/book/game/debug.tex b/book/game/debug.tex new file mode 100644 index 0000000..31901a7 --- /dev/null +++ b/book/game/debug.tex @@ -0,0 +1,122 @@ +\secrel{Отладка под эмулятором}\label{qemudebug}\secdown + +QEMU обеспечивает не только запуск \term{bare metal} программ в эмулиремой +виртуальной машине, но и полноценный отладочный интерфейс для GNU \file{gdb}. + +\lst{game/debug0.mk}{title=\file{/game/Makefile},language=make} + +\clearpage +PHONY-цель \file{go}\ идет в \file{Makefile} самой первой, и является главной +целью при запуске \verb|make [go]|. \file{game.elf}\ будет автоматически +перекомпилирован если вы меняли или удаляли какие-то зависимые файлы (с +исходным кодом), затем будет запущен QEMU в режиме \term{отладочного сервера}. +Режимы работы задаются с помощью опций командной строки: + +\begin{description}[nosep] +\item[-kernel game.elf] QEMU умеет загружать напрямую ядра операционных систем и +bare metal программы, в которых есть загрузочный заголовок Multiboot +\ref{multiboot}. Для запуска игр скомпилированных в ELF файлы вам не нужны +образы дисков\ --- все ресурсы игры вкомпилированы внутрь исполняемого +кода, и загрузчик ОС сам позаботится чтобы они были помещены в правильные +области ОЗУ. +\item[-nographic] отключить открытие окна эмулятора видеовывода VGA +\item[-s] включить \term{gdb-сервер} +\item[-S] ожидать подключения отладчика до запуска программы +\end{description} + +\clearpage +\begin{framed}\noindent +Умение пользоваться \term{отладчиком}\ --- \emph{критический навык} для +любого разработчика встраиваемых систем. +\end{framed} +\noindent +Вы это поймете как только соскочите с Одурины \ref{arduino}\ на любую другую +среду разработки для микроконтроллеров. Вместо того чтобы долбить команды +отладочного вывода на UART, через (аппаратный) отладчик вы получаете полноценный +интерактивный доступ ко всем внутренностям микроконтроллера или любой программы, +запущенной под операционной системой. +\note{ +Если какой-то великий специалист пытается вам усиленно доказывать, что для +разработки отладчик не нужен, и достаточно UART-команд устройства и отладочного +вывода, поздравляю\ --- вы наняли само\-учку-дяйвайщика. Такой ``специалист'' +подобен электронщику который настраивает схему с помощью китайского тестера и +лампочки вместо многоканального осциллографа и логического анализатора. Самое +смешное, что таких инженеров массово выпускают профильные технические кафедры +российских ``ВУЗ''ов, в нагрузку 146\% вы также получаете незнание о +существовании систем контроля версий, документирования кода, багтрекинга, +тестирования, и ведения проектной документации. +} + +% \clearpage +\url{http://www.linuxcenter.ru/lib/books/linuxdev/linuxdev9.phtml} + +\url{https://eax.me/gdb/} + +\medskip\noindent +Запуск отладчика состоит из двух частей: +\begin{description}[nosep] +\item[qemu] запускается в фоновом процессе, ожидая подключения на порту TCP +\file{127.0.0.1:1234} как \term{gdb-сервер} +\item[gdb] \emph{отладчик является (сетевым) \term{gdb-клиентом}} +опция \verb|-x game.elf.gdb| указывает скрипт с командами инициализации +отладочной сессии: +\end{description} +\lst{game/gdb0.gdb}{title=\file{/game/game.elf.gdb}} + +\clearpage +\secrel{Запуск отладчика с графической оболочкой} + +В \linux\ доступна интересная \term{отладочная оболочка} \file{ddd}, которая +обеспечивает не только работу любого gdb-клиента в графическом режиме, но и +\emph{отображение структур данных отлаживаемой программы в виде диаграмм}. + +\lst{game/debug1.mk}{title=\file{/game/Makefile},language=make} + +\clearpage +\fig{game/debug1A.png}{width=\textwidth} +\clearpage +\fig{game/debug1B.png}{width=\textwidth} +\clearpage +\fig{game/debug1C.png}{width=\textwidth} + +\clearpage +\secrel{Отладка прошивки на микроконтроллере} + +В случае микроконтроллера схема отладки сильно усложняется: +\bigskip + +\fig{/tmp/debug.pdf}{width=\textwidth} +\clearpage + +\begin{description} +\item[simulator] программный симулятор, взаимодействует с gdb-клиентом по +протоколу gdb (установки точек останова, пошаговая отладка, выдача информации +по регистрам и т.п.), именно эту схему мы используем с QEMU +\item[OpenOCD] ПО для взаимодействия с различными аппаратными +отладочными адаптерами JTAG/SWD, в том числе включает программную реализацию +JTAG для универсальных конвертеров USB/GPIO (FTDI). +\item[texane] специализированный пакет для взаимодействия с программаторами +STlink +\item[stub] программный компонент, \emph{выполняемый на устройстве как часть +прошивки} микроконтроллера, обеспечивает отладку по аппаратным интерфейсам +общего назначения (UART, Ethernet, TCP/IP,..) без применения специализированных +аппаратных отладчиков. +\end{description} + +Вся магия \term{удаленной отладки} реализуется за счет использования +\term{отладочного протокола gdb}: достаточно любым доступным способом +реализовать двусторонний обмен данными между клиентом на рабочей станции +разработчика, и сервером подключенным к отлаживаемой системе. + +В результате мы получаем возможность не только загружать прошивку, и отлаживать +ее, но и \emph{взаимодействовать напрямую с аппаратурой}: писать/читать +произвольные области памяти, менять состояние регистров, загружать и выполнять +произвольный код, выполнять автоматизированное тестирование аппаратуры и т.п. + +\bigskip +Со стороны программиста мы тоже имеем большую гибкость: можно использовать +графический интерфейс, предоставляемый средами разработки, пользоваться +отдельными отладочными оболочками типа \file{ddd}, самостоятельно +реализовать удобный вам интерфейс, или писать скрипты автоматизации. + +\secup diff --git a/book/game/debug0.mk b/book/game/debug0.mk new file mode 100644 index 0000000..2700943 --- /dev/null +++ b/book/game/debug0.mk @@ -0,0 +1,8 @@ +QEMU = qemu-system-i386 +GDB = $(CROSS)/$(TARGET)-gdb +CFLAGS += -g2 -O0 + +go: game.elf + # exit from QEMU: [Ctrl-A] [X] + $(QEMU) -kernel $< -nographic -s -S & + $(GDB) -x $<.gdb $< ; killall $(QEMU) diff --git a/book/game/debug1.mk b/book/game/debug1.mk new file mode 100644 index 0000000..3e5b682 --- /dev/null +++ b/book/game/debug1.mk @@ -0,0 +1,6 @@ +DDD = "$(GDB) -x $<.gdb $< ; killall $(QEMU)" + +go: game.elf + # exit from QEMU: [Ctrl-A] [X] + $(QEMU) -kernel $< -nographic -s -S & + ddd --debugger $(DDD) \ No newline at end of file diff --git a/book/game/debug1A.png b/book/game/debug1A.png new file mode 100644 index 0000000..78e64b3 Binary files /dev/null and b/book/game/debug1A.png differ diff --git a/book/game/debug1B.png b/book/game/debug1B.png new file mode 100644 index 0000000..e662ba1 Binary files /dev/null and b/book/game/debug1B.png differ diff --git a/book/game/debug1C.png b/book/game/debug1C.png new file mode 100644 index 0000000..0d78309 Binary files /dev/null and b/book/game/debug1C.png differ diff --git a/book/game/dev.tex b/book/game/dev.tex index 546ab3c..fd0cbe4 100644 --- a/book/game/dev.tex +++ b/book/game/dev.tex @@ -1,4 +1,4 @@ -\secrel{Разработка игр}\label{gamedev} +\secrel{Разработка игр}\label{gamedev}\secdown\secdown В качестве основы для этого раздела взята библия разработчиков игр\ -- книга Андре Ла Мота \cite{lamot}. Это первая и единственная книга на русском языке, @@ -12,4 +12,13 @@ на DOS и реальный режим процессоров 8086 смысла уже нет: запуск такого ПО потребует обязательного использования эмулятора DOSBOX, и при этом есть определенные проблемы с поиском легальных средства разработки для реального -режима 8086. +режима 8086. В этом разделе мы рассмотрим \file{QEMU-i386} и низкоуровневый код +как наиболее универсальный вариант, который вы при желании можете запустить на +реальном железе. + +\input{game/cross} +\input{game/debug} +\input{game/boot} +\input{game/video} + +\secup\secup diff --git a/book/game/gdb0.gdb b/book/game/gdb0.gdb new file mode 100644 index 0000000..d72d7e6 --- /dev/null +++ b/book/game/gdb0.gdb @@ -0,0 +1,2 @@ +target remote :1234 +b _start diff --git a/book/game/video.tex b/book/game/video.tex new file mode 100644 index 0000000..534e36d --- /dev/null +++ b/book/game/video.tex @@ -0,0 +1,5 @@ +\secrel{Видеосистема}\secdown + +\secrel{Инициализация VESA framebuffer} + +\secup diff --git a/book/gui/wx.tex b/book/gui/wx.tex index fef5ad4..c715936 100644 --- a/book/gui/wx.tex +++ b/book/gui/wx.tex @@ -20,15 +20,103 @@ Поддержка версии 2.7 закрыта, поэтому часть пакетов придется ставить не через \file{pip}, а индивидуальными инсталляторами. -\secrel{Базовый мультиоконный GUI} +\secrel{Базовый мультиоконный GUI}\secdown + +\url{https://python-scripts.com/wxpython} \clearpage \lst{gui/wx00.py}{language=Python,title=gui/wxide.py} -\begin{description} -\item[ide] -\item[ideWindow] -\item[ideConsole] +\begin{description}[nosep] +\item[ide] приложение wxWidgets, объект отслеживает логику GUI +\item[ideWindow] класс окна, формирует типовое окно IDE (редактор + меню) +\item[ideConsole] главное окно\ --- командная консоль \end{description} +\fig{gui/wx00.png}{height=.5\textheight} + +\lst{gui/wx01.py}{language=Python} +\fig{gui/wx01.png}{height=.3\textheight} + +\clearpage +\lst{gui/wx02.py}{language=Python} +\fig{gui/wx02.png}{height=.5\textheight} + +\clearpage +При запуске будем открывать файл командного скрипта по умолчанию, и хранить +привязку окна IDE к текстовому файлу: +\lst{gui/wx03.py}{language=Python} +\lst{gui/wx04.py}{language=Python} +\lst{gui/wx05.py}{language=Python} +Пока ограничимся привязкой каждого окна редактора к текстовому файлу: этот +функционал в любом случае необходим для чтения уже существующего кода, и +обеспечения совместимости с системами версионирования. +\clearpage +\lst{gui/wx06.py}{language=Python} +\fig{gui/wx06.png}{height=.5\textheight} + +\clearpage\noindent +Для интерактивной работы в IDE необходим импорт \F-машины из \metal. +Пока не будем явно выделять инстансы \class{FVM} \ref{FVM}, и используем +глобальную машину: +\lst{gui/wx07.py}{language=Python} +\noindent +Для интерактивной консоли необходим просмотр стека, и иногда словаря. Это +делается в отдельных окнах, обновляемых после выполнения команд: +\lst{gui/wx08.py}{language=Python} +\begin{verbatim} + @7fc8029e45f0 + @7fc8029e45a8 + EXECUTE = @7fc8029b30e0 + * = @7fc8029b3878 + >> = @7fc8029b3830 ... +\end{verbatim} + +\lst{gui/wx09.py}{language=Python} +Но эти окна не всегда нужны, поэтому желательно сделать их скрываемыми по +хоткею: +\lst{gui/wx10.py}{language=Python} + +\noindent +На кнопки F10/F11 назначим закрытие/открытие окон стека и словаря: +\lst{gui/wx11.py}{language=Python} +\lst{gui/wx12.py}{language=Python} +\lst{gui/wx13.py}{language=Python} +\lst{gui/wx14.py}{language=Python} + +\secrel{Обработка клавиш} + +\clearpage +\secrel{Визуализация фреймов} + +Для работы с развесистыми фреймовыми представлениями знаний\note{frame-based +\term{KRR}: Knowledge Representation and Reasoning}\ \emph{визуализация является +критическим функционалом}. Если взять даже простую программу на \emc\ размером +всего в 2-3 экрана, результат ее разбора уже будет содержать сотни +синтаксических узлов. Если пойти дальше, пытась объединять несколько программ, +выявлять общие шаблонные части, поддерживать варианты целевых систем и настроек, +или реализовать часть компилятора, сеть фреймов превращается в нечитаемую кашу +из сотен тысяч узлов. + +\begin{verbatim} +$ sudo pip install pydot networkx matplotlib +\end{verbatim} + +Для отрисовки графиков используется другой класс окон, в котором переназначен +метод инициализации редактора: вместо виджета текстового редатора Scintilla +используется канвас визуализатора: + +% \clearpage +\lst{gui/wx15.py}{language=Python} +\lst{gui/wx16.py}{language=Python} +\fig{gui/wx16.png}{height=.5\textheight} + +Более богатые возможности визуализации у библиотеки \file{networkx}. +\lst{gui/wx17.py}{language=Python} +\lst{gui/wx18.py}{language=Python} +\fig{gui/wx19.png}{width=\textwidth} + + +\secup + \secup \ No newline at end of file diff --git a/book/gui/wx00.png b/book/gui/wx00.png new file mode 100644 index 0000000..0329c94 Binary files /dev/null and b/book/gui/wx00.png differ diff --git a/book/gui/wx00.py b/book/gui/wx00.py index dc1e3d1..2aa7a28 100644 --- a/book/gui/wx00.py +++ b/book/gui/wx00.py @@ -6,6 +6,6 @@ class ideWindow(wx.Frame): def __init__(self,V): wx.Frame.__init__(self,parent=None,title=V) -ideConsole = ideWindow(sys.argv[0]) ; ideMain.Show() +ideConsole = ideWindow(sys.argv[0]) ; ideConsole.Show() ide.MainLoop() diff --git a/book/gui/wx01.png b/book/gui/wx01.png new file mode 100644 index 0000000..45fb4d2 Binary files /dev/null and b/book/gui/wx01.png differ diff --git a/book/gui/wx01.py b/book/gui/wx01.py new file mode 100644 index 0000000..5672cc0 --- /dev/null +++ b/book/gui/wx01.py @@ -0,0 +1,15 @@ +class ideWindow(wx.Frame): + def __init__(self,V): + wx.Frame.__init__(self,parent=None,title=V) + self.initMenu() + def initMenu(self): + self.menu = wx.MenuBar() + self.SetMenuBar(self.menu) + self.file = wx.Menu() + self.menu.Append(self.file,'&File') + + self.debug = wx.Menu() + self.menu.Append(self.debug,'&Debug') + + self.help = wx.Menu() + self.menu.Append(self.help,'&Help') diff --git a/book/gui/wx02.png b/book/gui/wx02.png new file mode 100644 index 0000000..3d80f65 Binary files /dev/null and b/book/gui/wx02.png differ diff --git a/book/gui/wx02.py b/book/gui/wx02.py new file mode 100644 index 0000000..37a855b --- /dev/null +++ b/book/gui/wx02.py @@ -0,0 +1,6 @@ + def initMenu(self): + self.save = self.file.Append(wx.ID_SAVE,'&Save') + self.quit = self.file.Append(wx.ID_EXIT,'&Quit') + self.Bind(wx.EVT_MENU,self.onQuit,self.quit) + def onQuit(self,event): + ideConsole.Close() diff --git a/book/gui/wx03.py b/book/gui/wx03.py new file mode 100644 index 0000000..dec6e5b --- /dev/null +++ b/book/gui/wx03.py @@ -0,0 +1,6 @@ +try: + autoloadFile = sys.argv[1] +except: + autoloadFile = 'wxide.src' + +ideConsole = ideWindow(autoloadFile) ; ideConsole.Show() \ No newline at end of file diff --git a/book/gui/wx04.py b/book/gui/wx04.py new file mode 100644 index 0000000..a2f1c1b --- /dev/null +++ b/book/gui/wx04.py @@ -0,0 +1,6 @@ +class ideWindow(wx.Frame): + def __init__(self,FileName): + wx.Frame.__init__(self,parent=None,title=FileName) + self.filename = FileName + self.initMenu() + self.initEditor() diff --git a/book/gui/wx05.py b/book/gui/wx05.py new file mode 100644 index 0000000..70ee9a6 --- /dev/null +++ b/book/gui/wx05.py @@ -0,0 +1,11 @@ +def initEditor(self): + self.editor = wx.stc.StyledTextCtrl(self) + self.onLoad() + +def onLoad(self): + try: + with open(self.filename) as F: + self.editor.SetValue(F.read()) ; F.close() + except IOError: # no file + self.editor.SetValue('# %s\n\n' % self.filename) + self.onSave() diff --git a/book/gui/wx06.png b/book/gui/wx06.png new file mode 100644 index 0000000..2565887 Binary files /dev/null and b/book/gui/wx06.png differ diff --git a/book/gui/wx06.py b/book/gui/wx06.py new file mode 100644 index 0000000..79efb57 --- /dev/null +++ b/book/gui/wx06.py @@ -0,0 +1,6 @@ +def onSave(self): + with open(self.filename,'w') as F: + F.write( self.editor.GetValue() ) ; F.close() +def initMenu(self): + self.save = self.file.Append(wx.ID_SAVE,'&Save') + self.Bind(wx.EVT_MENU,self.onSave,self.save) diff --git a/book/gui/wx07.py b/book/gui/wx07.py new file mode 100644 index 0000000..2d47f85 --- /dev/null +++ b/book/gui/wx07.py @@ -0,0 +1,2 @@ +sys.path += ['..'] +from metaL import * diff --git a/book/gui/wx08.py b/book/gui/wx08.py new file mode 100644 index 0000000..9790d8f --- /dev/null +++ b/book/gui/wx08.py @@ -0,0 +1,3 @@ +print S +print W +sys.exit() diff --git a/book/gui/wx09.py b/book/gui/wx09.py new file mode 100644 index 0000000..f2735b6 --- /dev/null +++ b/book/gui/wx09.py @@ -0,0 +1,9 @@ +class ideWindow(wx.Frame): + def onQuit(self,event): + ideConsole.onSave() ; ideConsole.Close() + ideStack.Close() ; ideWords.Close() + +ideStack = ideWindow(autoloadFile + '.stack') +ideStack.Show() +ideWords = ideWindow(autoloadFile + '.words') +ideWords.Show() diff --git a/book/gui/wx10.py b/book/gui/wx10.py new file mode 100644 index 0000000..bbaeb0c --- /dev/null +++ b/book/gui/wx10.py @@ -0,0 +1,15 @@ + def initMenu(self): + self.update = self.debug.Append( + wx.ID_REFRESH,'&Update\tF12') + self.Bind(wx.EVT_MENU,self.onUpdate,self.update) + self.stack = self.debug.Append( + wx.ID_ANY,'&Stack\tF11') + self.words = self.debug.Append( + wx.ID_ANY,'&Words\tF10') + def onUpdate(self,event): + ideStack.Show() ; ideWords.Show() + ideStack.editor.SetValue(S.dump()) + ideWords.editor.SetValue(W.dump()) + +ideStack = ideWindow(autoloadFile+'.stack') # don't show +ideWords = ideWindow(autoloadFile+'.words') # on start diff --git a/book/gui/wx11.py b/book/gui/wx11.py new file mode 100644 index 0000000..fd49aab --- /dev/null +++ b/book/gui/wx11.py @@ -0,0 +1,5 @@ +def initMenu(self): + self.stack = self.debug.Append(wx.ID_ANY,'&Stack\tF11') + self.Bind(wx.EVT_MENU,self.onStack,self.stack) + self.words = self.debug.Append(wx.ID_ANY,'&Words\tF10') + self.Bind(wx.EVT_MENU,self.onWords,self.words) diff --git a/book/gui/wx12.py b/book/gui/wx12.py new file mode 100644 index 0000000..1bb440c --- /dev/null +++ b/book/gui/wx12.py @@ -0,0 +1,3 @@ + def onStack(self,event): + if ideStack.IsShown(): ideStack.Hide() # toggle + else: ideStack.Show() diff --git a/book/gui/wx13.py b/book/gui/wx13.py new file mode 100644 index 0000000..6b3f068 --- /dev/null +++ b/book/gui/wx13.py @@ -0,0 +1,3 @@ + def onWords(self,event): + if ideWords.IsShown(): ideWords.Hide() + else: ideWords.Show() diff --git a/book/gui/wx14.py b/book/gui/wx14.py new file mode 100644 index 0000000..a209f68 --- /dev/null +++ b/book/gui/wx14.py @@ -0,0 +1,5 @@ + def onUpdate(self,event): + if ideStack.IsShown(): + ideStack.editor.SetValue(S.dump()) + if ideWords.IsShown(): + ideWords.editor.SetValue(W.dump()) diff --git a/book/gui/wx15.py b/book/gui/wx15.py new file mode 100644 index 0000000..b81a195 --- /dev/null +++ b/book/gui/wx15.py @@ -0,0 +1,13 @@ +import pydot +class ideWindow(wx.Frame): + def initMenu(self): + self.plot = self.debug.Append( + wx.ID_ANY,'&Plot\tCtrl+P') + self.Bind(wx.EVT_MENU,self.onPlot,self.plot) + def onPlot(self,event): + ideGraph.Show() + +class idePlot(ideWindow): + def initEditor(self): pass + +ideGraph = idePlot(autoloadFile + '.plot') diff --git a/book/gui/wx16.png b/book/gui/wx16.png new file mode 100644 index 0000000..93d630f Binary files /dev/null and b/book/gui/wx16.png differ diff --git a/book/gui/wx16.py b/book/gui/wx16.py new file mode 100644 index 0000000..d951ab0 --- /dev/null +++ b/book/gui/wx16.py @@ -0,0 +1,15 @@ +class idePlot(ideWindow): + def initEditor(self): + # plot to file + plot = pydot.Dot(graph_type='digraph') + for i in W.attr.keys(): + plot.add_edge(pydot.Edge( + W.value,W.attr[i].value)) + plot.write_png(self.filename) + # file to GUI widget + image = wx.Image(self.filename, + wx.BITMAP_TYPE_ANY) + self.editor = wx.StaticBitmap( + self,wx.ID_ANY,wx.BitmapFromImage(image)) + +ideGraph = idePlot (autoloadFile + '.png' ) diff --git a/book/gui/wx17.py b/book/gui/wx17.py new file mode 100644 index 0000000..4e09678 --- /dev/null +++ b/book/gui/wx17.py @@ -0,0 +1,6 @@ +from matplotlib.backends.backend_wxagg + import FigureCanvasWxAgg as FigureCanvas +from matplotlib.figure import Figure +# import matplotlib.pyplot as plt + +import networkx as nx diff --git a/book/gui/wx18.py b/book/gui/wx18.py new file mode 100644 index 0000000..a843efe --- /dev/null +++ b/book/gui/wx18.py @@ -0,0 +1,15 @@ +class idePlot(ideWindow): + def initEditor(self): + self.figure = Figure() + self.canvas = FigureCanvas(self, -1, self.figure) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.canvas, 1, + wx.LEFT | wx.TOP | wx.GROW) + self.SetSizer(self.sizer) + def onUpdate(self,event): + self.figure.clf() + self.axes = self.figure.add_subplot(111) + graph = nx.DiGraph() + for i in W.keys(): graph.add_edge(W, W[i]) + nx.draw(graph,ax=self.axes) + self.Fit() diff --git a/book/gui/wx19.png b/book/gui/wx19.png new file mode 100644 index 0000000..454365e Binary files /dev/null and b/book/gui/wx19.png differ diff --git a/book/header.tex b/book/header.tex index 396af62..e20f801 100644 --- a/book/header.tex +++ b/book/header.tex @@ -74,13 +74,19 @@ \subsection*{#1} \newcommand{\cp}[1]{\note{\copyright\ #1}} \newcommand{\term}[1]{\textcolor{green}{\textit{#1}}} \newcommand{\termdef}[2]{\textcolor{red}{\textbf{\textit{#1}}}\index{#2}} + \newcommand{\file}[1]{\texttt{#1}} +\newcommand{\class}[1]{\texttt{#1}} +\newcommand{\var}[1]{\texttt{#1}} +\newcommand{\fn}[1]{\texttt{#1}} % comp \newcommand{\emc}{$C$} \newcommand{\cpp}{$C^{+_+}$} \newcommand{\java}{$Java$} \newcommand{\py}{\texttt{\textbf{Python}}} +\newcommand{\rpy}{\texttt{\textbf{RPython}}} +\newcommand{\pp}{\texttt{\textbf{PyPy}}} \newcommand{\lisp}{$Lisp$} \newcommand{\F}{\texttt{\textbf{Форт}}} \newcommand{\js}{$JS$} @@ -91,6 +97,7 @@ \subsection*{#1} \newcommand{\self}{$Self$} \newcommand{\A}{Android} \newcommand{\eclipse}{Eclipse} +\newcommand{\vim}{(g)Vim} \newcommand{\linux}{Linux} \newcommand{\win}{Windows} \newcommand{\wasm}{WASM} @@ -110,6 +117,8 @@ \subsection*{#1} keywordstyle=\color{red}, commentstyle=\color{blue}, extendedchars=\true, +% fix russian comments: https://dxdy.ru/post509540.html +keepspaces = true, %breaklines=false,breakatwhitespace=true } \newcounter{lstcounter} diff --git a/book/mcu/debug.dot b/book/mcu/debug.dot new file mode 100644 index 0000000..f0ea51f --- /dev/null +++ b/book/mcu/debug.dot @@ -0,0 +1,24 @@ +digraph { +rankdir=LR; +STM32 [shape=Msquare,label="STM32\nMCU"]; +STlink [shape=Mdiamond,label="STLink\nv.2-1"]; +STM32 -> STlink [label=SWD]; +STlink-> texane -> OpenOCD -> gdb -> ddd; +texane [label="texane\nstlink"]; +gdb -> Eclipse; +simulator -> gdb [label=TCP]; +MSP430 [shape=Msquare]; +MSP430 -> stub [label="firmware\npart"]; +stub -> gdb [label="serial\nUART"]; +{ rank=same; MSP430; STM32; ARM; } +{ rank=same; STlink; stub; Segger; } +Segger [shape=Mdiamond,label="Segger\nJ-LINK"]; +{ rank=same; texane; simulator; } +ARM -> Segger [label=JTAG]; +Segger -> OpenOCD [label=USB]; +ARM [shape=parallelogram]; +ARM [label="ARM\nboard"]; +{ rank=same; gdb; ddd; Eclipse; } +ddd [shape=box]; +Eclipse [shape=box]; +} diff --git a/book/meta/circ.tex b/book/meta/circ.tex index fdfd0c1..9be28a1 100644 --- a/book/meta/circ.tex +++ b/book/meta/circ.tex @@ -76,22 +76,6 @@ \F. Одновременно \file{metaL.ini} также является последним этапом интеграционного тестирования, проверяющим работу всех фич языка. -\secrel{Файлы проекта}\label{circfiles} - -\lst{meta/files.ini}{} -\lst{meta/eclfiles.ini}{} -\lst{meta/ebldfiles.ini}{} -\lst{meta/vimfiles.ini}{} - -Начиная новый программный проект, мы каждый раз снова и снове делаем одни и те -же действия, даже используя визард в вашей любимой IDE: создать структуру -каталогов, прописать маски производных файлов для git, задать -мультиплатформенную кодировку для файлов и т.д. При этом от проекта к проекту -некоторые файлы немного меняются, особенно это относится к Makefile и другим -файлам, хранящим список компилируемых модулей или опции компиляции. -Для встраиваемых систем самым геморным будет постоянно отслеживать список файлов -и своевременно обновлять Makefile. И в итоге, для -автогенерируемого кода нам нужно автоматизировать и создание Makefile отслеживая -зависимости между множеством файлов. +\input{meta/ouro/boros} \secup \ No newline at end of file diff --git a/book/meta/ouro/boros.png b/book/meta/ouro/boros.png new file mode 100644 index 0000000..e3ce255 Binary files /dev/null and b/book/meta/ouro/boros.png differ diff --git a/book/meta/ouro/boros.tex b/book/meta/ouro/boros.tex new file mode 100644 index 0000000..e1d1c10 --- /dev/null +++ b/book/meta/ouro/boros.tex @@ -0,0 +1,42 @@ +\secrel{Ouroboros: минималистичный форк \metal}\label{ouro}\secdown + +\noindent +\begin{tabular}{l p{7.7cm}} +\multirow{1}{*}{\fig{meta/ouro/boros.png}{height=.5\textheight}} & + +\url{https://github.com/ponyatov/Ouroboros} + +\medskip +\noindent +В отдельный проект была выделена специальная минималистичная версия \metal: +никакой документации, всего несколько файлов, и функциональность необходимая +только для трансляции метамодели на \metal\ в интерпретатор на \py. + +{\scriptsize (*) это Python который ест сам себя. это хвост}\\ +\end{tabular} +\medskip + +\noindent +Весь ввод/вывод ограничен только выводом строк на консоль, для экспериментов +доступна текстовая REPL-консоль, доступ к которой можно получить в окне работы +интерпретатора \py\ в \eclipse. Для работы под \win\ сделана легкая адаптация +для запуска сессии в \vim, что добавило несколько файлов, загромождающих каталог +проекта. + +\clearpage +\emph{Запись в файлы не поддерживается}: вы должны вручную скопировать +куски исходного кода из консоли, вручную проверяя их корректность при замене в +коде интерпретатора. + +Смысл отдельного проекта в том, чтобы выделить минимальное самодостаточное +\term{ядро \metal}, способное оттранслировать только самого себя, не таская всю +мощь большой системы, и \emph{зафиксировать} это ядро. Маленький объем кода +упрощает изучение, интеграцию в другие системы, и портирование интерпретатора на +другие языки. Одноременно метамодель, написанная на \metal, становится +\term{формальной спецификацией языка}, так как она не пререгружена фичами, +библиотеками и другой информацией. + +\input{meta/ouro/info} +\input{meta/ouro/files} + +\secup diff --git a/book/meta/ouro/files.tex b/book/meta/ouro/files.tex new file mode 100644 index 0000000..b52976c --- /dev/null +++ b/book/meta/ouro/files.tex @@ -0,0 +1,19 @@ +\clearpage +\secrel{Файлы проекта}\label{circfiles} + +% \lst{meta/files.ini}{} +% \lst{meta/eclfiles.ini}{} +% \lst{meta/ebldfiles.ini}{} +% \lst{meta/vimfiles.ini}{} + +Начиная новый программный проект, мы каждый раз снова и снове делаем одни и те +же действия, даже используя визард в вашей любимой IDE: создать структуру +каталогов, прописать маски производных файлов для git, задать +мультиплатформенную кодировку для файлов и т.д. При этом от проекта к проекту +некоторые файлы немного меняются, особенно это относится к Makefile и другим +файлам, хранящим список компилируемых модулей или опции компиляции. +Для встраиваемых систем самым геморным будет постоянно отслеживать список файлов +и своевременно обновлять Makefile. И в итоге, для +автогенерируемого кода нам нужно автоматизировать и создание Makefile отслеживая +зависимости между множеством файлов. + diff --git a/book/meta/ouro/info.ml b/book/meta/ouro/info.ml new file mode 100644 index 0000000..796a46b --- /dev/null +++ b/book/meta/ouro/info.ml @@ -0,0 +1,7 @@ +module: Ouroboros `MODULE ! +'metaL programming language' +' (metacircular implementation)' + `TITLE ! +'Dmitry Ponyatov <>' `AUTHOR ! +'CC BY-NC-ND' `LICENSE ! +'https://github.com/ponyatov/Ouroboros' `GITHUB ! +'ouroboros.png' `LOGO ! \ No newline at end of file diff --git a/book/meta/ouro/info.tex b/book/meta/ouro/info.tex new file mode 100644 index 0000000..d725b2f --- /dev/null +++ b/book/meta/ouro/info.tex @@ -0,0 +1,4 @@ +\clearpage +\secrel{Метаинформация о программном модуле}\label{ouroinfo} + +\lst{meta/ouro/info.ml}{} \ No newline at end of file diff --git a/book/metaL.tex b/book/metaL.tex index 64946a7..f8df4a5 100644 --- a/book/metaL.tex +++ b/book/metaL.tex @@ -78,6 +78,8 @@ \part{Реализация в деталях}\label{implement}\secdown \input{syntax/syntax} +\input{py/py} + \input{docu/ment} \input{bib/bib} diff --git a/book/os.tex b/book/os.tex deleted file mode 100644 index d6d7f2a..0000000 --- a/book/os.tex +++ /dev/null @@ -1,2 +0,0 @@ -\secrel{met: метаОС для встраиваемых систем}\label{os}\secdown -\secup diff --git a/book/py/hello00.py b/book/py/hello00.py new file mode 100644 index 0000000..b90a7f3 --- /dev/null +++ b/book/py/hello00.py @@ -0,0 +1,11 @@ +import sys + +def main(argv): + print 'hello' + +def target(*args): + return main,None + +# this will run main() in interpreter mode (CPython/pypy) +if __name__ == '__main__': + main(sys.argv) diff --git a/book/py/py.tex b/book/py/py.tex new file mode 100644 index 0000000..91492a1 --- /dev/null +++ b/book/py/py.tex @@ -0,0 +1,62 @@ +\secrel{Реализация ядра \metal\ на \pp}\label{pypy}\secdown + +\noindent +\pp\ был задуман как реализация \py, написанная на \py, но благодаря наличию +фреймворка для реализации динамических языков программирования он является также +средством разработки новых языков программирования. +\pp\ состоит из стандартного интерпретатора и транслятора: +\begin{description} +\item[Интерпретатор] полностью реализует язык \py. Сам интерпретатор написан +на ограниченном подмножестве этого же языка, называемом \rpy\ (Restricted +Python). В отличие от стандартного \py, \rpy\ является статически +типизированным для более эффективной компиляции. +\item[Транслятор] является набором инструментов, который анализирует код \rpy\ и +переводит его в языки более низкого уровня, такие как \emc, байт-код \java\ или +CIL. Он также поддерживает подключаемые сборщики мусора и позволяет опционально +включать Stackless. +\item[JIT-компилятор] также \pp\ включает опциональный модуль встроенного +компилятора для трансляции кода в машинные инструкции во время исполнения +программы. +\end{description} + +% \clearpage +\subsecly{Установка} + +\begin{verbatim} +$ sudo apt update +$ sudo apt install pypy +$ sudo pip install -U rpython +\end{verbatim} + +\pp\ может быть запущен как обычный интерпретатор: + +\begin{verbatim} +$ pypy py/hello.py + +hello +\end{verbatim} + +\clearpage +Для получения быстрого исполняемого файла запускаем транслятор \rpy: +\begin{verbatim} +$ rpython hello.py +\end{verbatim} + +% \bigskip +% \href{https://buildmedia.readthedocs.org/media/pdf/building-an-interpreter-with-rpython/latest/building-an-interpreter-with-rpython.pdf}{Tutorial +% on CyCy (интерпретатор Си)} + +\begin{itemize} + \item +\href{https://morepypy.blogspot.com/2011/04/tutorial-writing-interpreter-with-pypy.html}{Andrew +Brown tutorial part 1} +\end{itemize} + +\clearpage +Транслируемый модуль должен определять функцию \fn{target()} которая возвращает +точку входа. Транслятор работает с использованием метода \term{трассирующей +компиляции}, вызывая импортированный модуль через точку входа. + +\lst{py/hello00.py}{language=Python} + +\secup diff --git a/book/syntax/ply/lex.py b/book/syntax/ply/lex.py new file mode 100644 index 0000000..d670c98 --- /dev/null +++ b/book/syntax/ply/lex.py @@ -0,0 +1 @@ +import ply.lex as lex \ No newline at end of file diff --git a/book/syntax/ply/ply.tex b/book/syntax/ply/ply.tex new file mode 100644 index 0000000..4c22a56 --- /dev/null +++ b/book/syntax/ply/ply.tex @@ -0,0 +1 @@ +\secrel{PLY: библиотека синтаксического разбора для \py}\label{ply}\secdown \clearpage Библиотека PLY позволяет писать \term{парсеры} для достаточно сложных языков. Если вам для какой-то задачи потребуется применение \term{инфиксного синтаксиса}, типа разбора арифметических выражений, вы сможете без особых усилий добавить для них \term{синтаксический анализатор}. \begin{description} \item[Лексер] обрабатывает \term{входной поток} единичных символов из файла или строки, группируя их в \term{токены}. Каждый токен имеет тип \verb|.type|, значение \verb|.value|, и дополнительные поля типа имени файла исходного кода, или позиции токена (строка, столбец). \item[Парсер синтаксиса]\ читает \term{поток токенов}, или работает напрямую с символами и текстовыми строками, в зависимости от того, какие алгоритмы разоработа используются. \end{description} \clearpage \lst{syntax/ply/lex.py}{language=Python} \lst{syntax/ply/yacc.py}{language=Python} \term{Парсер} может состоять из обоих компонентов, или только из одного, в зависимости от сложности синтаксиса входного языка, и того, нужно ли нам \term{распознавать} рекурсивно вложенные синтаксические конструкции, или достаточно только определить тип \term{лексем} (для подстветки синтаксиса). \clearpage Каждое правило лексера задается в виде функции, её docstring задает регулярное выражение, которому должна удовлетворять группа символов, чтобы быть распознанной. Функция получает на вход параметр \verb|t| содержащий \textit{состояние лексера}; \verb|t.value| содержит распознанную группу символов в виде строки, которую мы возвращаем из функции через вызов конструктора фрейма соответствующего типа. \bigskip \noindent \verb|ply.lex.lex()| проходит по исходному коду текущего модуля \py, находит функции соответствующие шаблону правил лексера, и синтезирует функцию-лексер. \secrel{\F\ лексер}\label{plyforth} Несмотря на то что диалекты \F/\pyf\ требуют только реализацию \term{лексера}, есть смысл немного сэкономить усилия, и не заморачиваться с написанием традиционного посимвольного разбора ``до пробела''. Еще одно достоинство использования PLY: с ее помощью мы можем автоматически определять тип для каждой лексемы, в частности разпознавать примитивные типы \ref{prim}\ и вызывать соответствующие конструкторы. \begin{description}%[nosep] \item[tokens] список токенов, которые может распознавать парсер\\ так как мы специально обеспечили возможность использования фрей\-мов-примитивов в качестве \term{литералов}, в этом списке должны быть перечислены тэги (c маленькой буквы) \item[t\_ignore] символы которые не будут участвовать в разборе (пробелы) \item[t\_number()] правило лексера распознающее числа \item[t\_symbol()] правило распознающее символы как имена форт-слов \item[t\_error()] обработка синтаксических ошибок: нераспознанные символы \end{description} \secup \ No newline at end of file diff --git a/book/syntax/ply/yacc.py b/book/syntax/ply/yacc.py new file mode 100644 index 0000000..476eef1 --- /dev/null +++ b/book/syntax/ply/yacc.py @@ -0,0 +1 @@ +import ply.yacc as yacc \ No newline at end of file diff --git a/book/syntax/ragel/java.tex b/book/syntax/ragel/java.tex index 44846f4..34f3168 100644 --- a/book/syntax/ragel/java.tex +++ b/book/syntax/ragel/java.tex @@ -1,12 +1,12 @@ \secrel{Использование \file{ragel} для лексера на Java}\label{rageljava}\secdown -Ragel\ --- компилятор конечных автоматов, производящий исходный код на C, C++, -C\#, Objective-C, D, Java \ref{rageljava}, OCaml, Go и Ruby. - -\url{http://thingsaaronmade.com/blog/a-simple-intro-to-writing-a-lexer-with-ragel.html} - -\url{http://www.colm.net/open-source/ragel/} +Для реализации командного интерфейса на диалекте \F\ для \A-реализации \metal\ +\ref{anconsole}\ используется \file{ragel}. Эта утилита умеет гененировать +исходный код на множестве языков программирования, в том числе и \java. +\lst{syntax/ragel/java00.Makefile}{title=/Android/Makefile,language=make} +\clearpage +\lst{syntax/ragel/java00.ragel}{title=/Android/FORTH.ragel,language=Java} \secup diff --git a/book/syntax/ragel/java00.Makefile b/book/syntax/ragel/java00.Makefile new file mode 100644 index 0000000..5ef43e5 --- /dev/null +++ b/book/syntax/ragel/java00.Makefile @@ -0,0 +1,4 @@ +SRC = app/src/main/java/ +PKG = $(SRC)/io/github/ponyatov/metal +$(PKG)/FORTH.java: FORTH.ragel Makefile + ragel -J -o $@ $< diff --git a/book/syntax/ragel/java00.ragel b/book/syntax/ragel/java00.ragel new file mode 100644 index 0000000..a237e1c --- /dev/null +++ b/book/syntax/ragel/java00.ragel @@ -0,0 +1,6 @@ +package io.github.ponyatov.metal; + +%%{ + machine lexer; + main := any; +}%% diff --git a/book/syntax/ragel/ragel.tex b/book/syntax/ragel/ragel.tex index fa3ee58..a42aa2e 100644 --- a/book/syntax/ragel/ragel.tex +++ b/book/syntax/ragel/ragel.tex @@ -1,3 +1,12 @@ \secrel{Генератор лексеров \file{Ragel}}\label{ragel}\secdown + +Ragel\ --- компилятор конечных автоматов, производящий исходный код на C, C++, +C\#, Objective-C, D, Java \ref{rageljava}, OCaml, Go и Ruby. + +\url{http://thingsaaronmade.com/blog/a-simple-intro-to-writing-a-lexer-with-ragel.html} + +\url{http://www.colm.net/open-source/ragel/} + \input{syntax/ragel/java} + \secup diff --git a/book/syntax/syntax.tex b/book/syntax/syntax.tex index d1911ef..6c5cde0 100644 --- a/book/syntax/syntax.tex +++ b/book/syntax/syntax.tex @@ -1,5 +1,6 @@ \secrel{Трансляторы и языковые инструменты}\secdown \input{syntax/ragel/ragel.tex} +\input{syntax/ply/ply.tex} \secup \ No newline at end of file diff --git a/codein/codein.py b/codein/codein.py index b97b198..03fb92e 100644 --- a/codein/codein.py +++ b/codein/codein.py @@ -79,7 +79,7 @@ def t_number(t): class Symbol(Source): pass def t_symbol(t): r'[a-zA-Z0-9_]+' - return Symbol(t) + t.value = Symbol(t) ; return t class Semicolon(Source): pass def t_semicolon(t): @@ -170,6 +170,8 @@ def t_error(t): raise SyntaxError(t) def p_error(p): raise SyntaxError(p) def p_repl_none(p): ' repl : ' +def p_repl_comment(p): + ' repl : repl comment ' def p_repl_recur(p): ' repl : repl expression ' print p[2], p[2].__class__ @@ -180,6 +182,11 @@ def p_ex_include(p): print p[2],p[2].__class__ p[0] = p[1].nest.append(p[2]) +def p_ex_vardef(p): + ' expression : symbol symbol semicolon ' +# p[0] = p[1] / p[2] ; + print p[1]/p[2] ; sys.exit(0) + lexer = lex.lex() parser = yacc.yacc(debug=False, write_tables=False) diff --git a/codein/doc/paper543.pdf b/codein/doc/paper543.pdf new file mode 100644 index 0000000..069fe08 Binary files /dev/null and b/codein/doc/paper543.pdf differ diff --git a/game/.gitignore b/game/.gitignore new file mode 100644 index 0000000..1b8f0d5 --- /dev/null +++ b/game/.gitignore @@ -0,0 +1,8 @@ +*.o +*.elf +*.kernel +*.objdump + +tmp/ +i?86-elf/ + diff --git a/game/Makefile b/game/Makefile new file mode 100644 index 0000000..5198398 --- /dev/null +++ b/game/Makefile @@ -0,0 +1,41 @@ + +CPU = i386 +TARGET = $(CPU)-elf +CFG_CPU = --with-cpu=$(CPU) +CROSS = $(CURDIR)/$(TARGET)/bin + +QEMU = qemu-system-i386 +GDB = $(CROSS)/$(TARGET)-gdb +CFLAGS += -g2 -O0 + +DDD = "$(GDB) -x $<.gdb $< ; killall $(QEMU)" + +go: game.elf + # exit from QEMU: [Ctrl-A] [X] + $(QEMU) -kernel $< -nographic -s -S & + ddd --debugger $(DDD) + +cross: ../mcu/Makefile + make -f $< TARGET=$(TARGET) CFG_CPU="$(CFG_CPU)" cross0 +clean: ../mcu/Makefile + make -f $< TARGET=$(TARGET) clean + +C = multiboot.S +H = multiboot.h + +GCC = $(CROSS)/$(TARGET)-gcc +CFLAGS += -march=$(CPU) -mtune=$(CPU) -m32 -I$(CURDIR) + +LD = $(CROSS)/$(TARGET)-ld +LDFLAGS = -m elf_i386 -T multiboot.ld + +OBJDUMP = LANG=C $(CROSS)/$(TARGET)-objdump + +game.elf: multiboot.o + $(LD) $(LDFLAGS) -o $@ $^ + $(OBJDUMP) -x -d $@ > $@.objdump + +multiboot.o: multiboot.S multiboot.h Makefile + $(GCC) $(CFLAGS) -c -o $@ $< + $(OBJDUMP) -x -d $@ > $@.objdump + diff --git a/game/boot.c b/game/boot.c new file mode 100644 index 0000000..1679719 --- /dev/null +++ b/game/boot.c @@ -0,0 +1,5 @@ +void boot(void) { + for(;;); +} + +void _start(void) { boot(); } diff --git a/game/game.elf.gdb b/game/game.elf.gdb new file mode 100644 index 0000000..3091534 --- /dev/null +++ b/game/game.elf.gdb @@ -0,0 +1,3 @@ +target remote :1234 +b _start +c diff --git a/game/multiboot.S b/game/multiboot.S new file mode 100644 index 0000000..a9607cc --- /dev/null +++ b/game/multiboot.S @@ -0,0 +1,33 @@ +/* Multiboot1 spec */ + +/* http://www.gnu.org/software/grub/manual/multiboot/multiboot.html */ + +#define ASM +#include + + .section .multiboot +_start: + jmp _init + + .align 4 +multiboot_header: + .long MULTIBOOT_HEADER_MAGIC + .long MULTIBOOT_HEADER_FLAGS + .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) + .long multiboot_header + .long _start + .long _edata + .long _end + .long _init + +_init: + + /* init stack pointer */ + movl $(_stack + STACK_SIZE), %esp + /* reset EFLAGS */ + pushl $0 + popf + /* mutiboot info structure */ + pushl %ebx + /* push magic value */ + pushl %eax diff --git a/game/multiboot.h b/game/multiboot.h new file mode 100644 index 0000000..a476ebd --- /dev/null +++ b/game/multiboot.h @@ -0,0 +1,31 @@ +/* Multiboot1 spec */ + +/* http://www.gnu.org/software/grub/manual/multiboot/multiboot.html */ + +#ifndef _H_MULTIBOOT +#define _H_MULTIBOOT + +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 +#define MULTIBOOT_HEADER_FLAGS 0x00000003 +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +#define STACK_SIZE 0x4000 + +#ifndef ASM + +/* The Multiboot header. */ +typedef struct multiboot_header +{ + uint32_t magic; + uint32_t flags; + uint32_t checksum; + uint32_t header_addr; + uint32_t load_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; + uint32_t entry_addr; +} multiboot_header_t; + +#endif // ASM + +#endif // _H_MULTIBOOT diff --git a/game/multiboot.ld b/game/multiboot.ld new file mode 100644 index 0000000..39297db --- /dev/null +++ b/game/multiboot.ld @@ -0,0 +1,31 @@ +OUTPUT_FORMAT(elf32-i386) + +MEMORY { + RAM : ORIGIN = 1M , LENGTH = 64M + SCREEN : ORIGIN = 0xB8000 , LENGTH = 80*25*2 + VESA : ORIGIN = 0xA0000 , LENGTH = 1024*768*3 +} + +SECTIONS { + + .text : { *(.multiboot) *(.text) } >RAM + _etext = . ; + + _data = . ; + .data : { *(.data) } >RAM + _edata = . ; + + _bstart = . ; + .bss : { *(.bss) *(COMMON) } >RAM + _bend = . ; + + _edata = . ; + _end = . ; + + _stack = . ; + .stack : { *(.stack) } >RAM + _estack = . ; + + .screen : { *(.screen) } >SCREEN + .vesa : { *(.vesa) } >VESA +} diff --git a/gui/.gitignore b/gui/.gitignore new file mode 100644 index 0000000..02c1c23 --- /dev/null +++ b/gui/.gitignore @@ -0,0 +1,6 @@ +autorun.inf + +*.src.stack +*.src.words +*.src.png + diff --git a/gui/bat.bat b/gui/bat.bat new file mode 100644 index 0000000..435cbd2 --- /dev/null +++ b/gui/bat.bat @@ -0,0 +1,2 @@ +python wxide.py +pause diff --git a/gui/logo.png b/gui/logo.png new file mode 100644 index 0000000..ea4aaca Binary files /dev/null and b/gui/logo.png differ diff --git a/gui/metaL.py b/gui/metaL.py new file mode 120000 index 0000000..5061c6c --- /dev/null +++ b/gui/metaL.py @@ -0,0 +1 @@ +../metaL.py \ No newline at end of file diff --git a/gui/wxide.py b/gui/wxide.py new file mode 100644 index 0000000..0700d59 --- /dev/null +++ b/gui/wxide.py @@ -0,0 +1,135 @@ +import sys,re +import wx,wx.stc,wx.lib.scrolledpanel + +from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas +from matplotlib.figure import Figure +# import matplotlib.pyplot as plt + +import networkx as nx + +sys.path += ['..'] +from metaL import * + +ide = wx.App() + +class ideWindow(wx.Frame): + + icon = wx.Icon('logo.png') + + def __init__(self,FileName): + wx.Frame.__init__(self,parent=None,title=FileName) + self.filename = FileName + self.initMenu() + self.initEditor() + self.SetIcon(self.icon) + + def initEditor(self): + self.editor = wx.stc.StyledTextCtrl(self) + self.onLoad() + + def onLoad(self,event=None): + try: + with open(self.filename) as F: + self.editor.SetValue(F.read()) ; F.close() + except IOError: # no file + self.editor.SetValue('# %s\n\n' % self.filename) + self.onSave() + + def onSave(self,event=None): + with open(self.filename,'w') as F: + F.write( self.editor.GetValue() ) ; F.close() + + def initMenu(self): + self.menu = wx.MenuBar() ; self.SetMenuBar(self.menu) + + self.file = wx.Menu() ; self.menu.Append(self.file,'&File') + self.save = self.file.Append(wx.ID_SAVE,'&Save\tCtrl+S') + self.Bind(wx.EVT_MENU,self.onSave,self.save) + self.quit = self.file.Append(wx.ID_EXIT,'&Quit\tCtrl+Q') + self.Bind(wx.EVT_MENU,self.onQuit,self.quit) + + self.debug = wx.Menu() ; self.menu.Append(self.debug,'&Debug') + self.update = self.debug.Append(wx.ID_REFRESH,'&Update\tF12') + self.Bind(wx.EVT_MENU,self.onUpdate,self.update) + self.stack = self.debug.Append(wx.ID_ANY,'&Stack\tF11') + self.Bind(wx.EVT_MENU,self.onStack,self.stack) + self.words = self.debug.Append(wx.ID_ANY,'&Words\tF10') + self.Bind(wx.EVT_MENU,self.onWords,self.words) + self.plot = self.debug.Append(wx.ID_ANY,'&Plot\tCtrl+P') + self.Bind(wx.EVT_MENU,self.onPlot,self.plot) + + self.help = wx.Menu() ; self.menu.Append(self.help,'&Help') + self.about = self.help.Append(wx.ID_ABOUT,'&About\tF1') + self.Bind(wx.EVT_MENU,self.onAbout,self.about) + + def onQuit(self,event): + ideConsole.onSave() + ideConsole.Close() ; ideStack.Close() ; ideWords.Close() + ideGraph.Close() + + def onAbout(self,event): + info = wx.AboutDialogInfo() + info.Icon = self.icon + info.Name = 'metaL/wx' + info.License = 'CC BY-NC-ND' + info.WebSite = 'https://github.com/ponyatov/metaL/releases' + info.Developers = ['Dmitry Ponyatov '] + info.Description = 'homoiconic metaprogramming language' + wx.AboutBox(info) + + def onStack(self,event): + if ideStack.IsShown(): ideStack.Hide() + else: ideStack.Show() ; ideStack.onUpdate(event) + + def onWords(self,event): + if ideWords.IsShown(): ideWords.Hide() + else: ideWords.Show() ; ideWords.onUpdate(event) + + def onPlot(self,event): + if ideGraph.IsShown(): ideGraph.Hide() + else: ideGraph.Show() ; ideGraph.onUpdate(event) + + def onUpdate(self,event): + if ideStack.IsShown(): + ideStack.editor.SetValue(S.dump()) + if ideWords.IsShown(): + ideWords.editor.SetValue(W.dump()) + +class idePlot(ideWindow): +# def __init__(self,V): +# ideWindow.__init__(self,V) +# self.Bind(wx.EVT_SET_FOCUS, self.onFocus) +# def onFocus(self,event): +# ideConsole.SetFocus() + + def initEditor(self): + self.figure = Figure() + self.canvas = FigureCanvas(self, -1, self.figure) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) + self.SetSizer(self.sizer) + + def onUpdate(self,event): + if self.IsShown(): + self.figure.clf() ; self.axes = self.figure.add_subplot(111) + graph = nx.DiGraph() + W.graph(graph) +# for i in W.keys(): graph.add_edge(W.value, W[i].value) + pos = nx.spring_layout(graph) + nx.draw_networkx_edges(graph,pos=pos,ax=self.axes,alpha=.2) + nx.draw_networkx_nodes(graph,pos=pos,ax=self.axes,alpha=.1) + nx.draw_networkx_labels(graph,pos=pos,ax=self.axes) + self.Fit() + +try: + autoloadFile = sys.argv[1] +except: + autoloadFile = re.sub(r'\.py$',r'.src',sys.argv[0]) + +ideConsole = ideWindow(autoloadFile) ; ideConsole.Show() + +ideStack = ideWindow(autoloadFile + '.stack') +ideWords = ideWindow(autoloadFile + '.words') +ideGraph = idePlot (autoloadFile + '.png' ) + +ide.MainLoop() diff --git a/gui/wxide.src b/gui/wxide.src new file mode 100644 index 0000000..47f14f2 --- /dev/null +++ b/gui/wxide.src @@ -0,0 +1,5 @@ +# wxide.src +1 2 + 345 + 11 + diff --git a/mcu b/mcu index 480af40..89b32b8 160000 --- a/mcu +++ b/mcu @@ -1 +1 @@ -Subproject commit 480af402e84f76e849ee15742426cde5cb385134 +Subproject commit 89b32b82b2664067437a0dc0a19b9b6ed4767168 diff --git a/metaL.py b/metaL.py index 6cda5ab..da5eaec 100644 --- a/metaL.py +++ b/metaL.py @@ -2,7 +2,6 @@ ## (c) Dmitry Ponyatov CC BY-NC-ND import os,sys -from wtforms.fields.simple import SubmitField ######################################################################## FRAMES @@ -51,6 +50,8 @@ def __getitem__(self,slot): return self.attr[slot] def __setitem__(self,slot,obj): self.attr[slot] = obj ; return self + def keys(self): + return self.attr.keys() ## stack manipulations @@ -64,6 +65,17 @@ def press(self): del self.nest[-2] ; return self def swap(self): B = self.pop() ; A = self.pop() ; self // B // A ; return self + ## plotting + + graphed = [] + def graph(self,kxgraph,depth=0): + if not depth: Frame.graphed = [] + if self not in Frame.graphed: + Frame.graphed.append(self) + for i in self.attr: + kxgraph.add_edge(self.value,i) + self.attr[i].graph(kxgraph,depth+1) + ## processing def execute(self): S // self @@ -130,20 +142,25 @@ def __setitem__(self,slot,obj): if callable(obj): self[slot] = VM(obj) ; return self else: return Container.__setitem__(self, slot, obj) def __lshift__(self,obj): - if callable(obj): self << VM(obj) ; return self + if callable(obj): self << CMD(obj) ; return self else: return Container.__lshift__(self, obj) ######################################################################## active class Active(Frame): pass -class VM(Active): +class CMD(Active): def __init__(self,F): Active.__init__(self,F.__name__) self.fn = F def execute(self): self.fn() +class VM(Active): pass +class FVM(VM): pass + +class Context(Active): pass + ########################################################################## meta class Meta(Frame): pass @@ -203,7 +220,7 @@ def t_error(t): raise SyntaxError(t) def QUOTE(): WORD() -W['`'] = VM(QUOTE) +W['`'] = CMD(QUOTE) def WORD(): token = lexer.token() @@ -257,7 +274,7 @@ def BYE(): def Sdot(): print S -W['?'] = VM(Sdot) +W['?'] = CMD(Sdot) def WORDS(): print W @@ -265,7 +282,7 @@ def WORDS(): def DumpExit(): WORDS() ; Sdot() ; BYE() -W['??'] = VM(DumpExit) +W['??'] = CMD(DumpExit) ################################################################### stack fluff @@ -283,17 +300,17 @@ def PRESS(): S.press() def DOT(): S.dropall() -W['.'] = VM(DOT) +W['.'] = CMD(DOT) ################################################################# manipulations def PUSH(): B = S.pop() ; S.top() // B -W['//'] = VM(PUSH) +W['//'] = CMD(PUSH) def RSHIFT(): WORD() ; FIND() ; B = S.pop() ; A = S.pop() ; A >> B -W['>>'] = VM(RSHIFT) +W['>>'] = CMD(RSHIFT) ################################################################### definitions @@ -305,23 +322,23 @@ def DEF(): def ADD(): B = S.pop() ; A = S.pop() ; S // A.add(B) -W['+'] = VM(ADD) +W['+'] = CMD(ADD) def SUB(): B = S.pop() ; A = S.pop() ; S // A.sub(B) -W['-'] = VM(SUB) +W['-'] = CMD(SUB) def MUL(): B = S.pop() ; A = S.pop() ; S // A.mul(B) -W['*'] = VM(MUL) +W['*'] = CMD(MUL) def DIV(): B = S.pop() ; A = S.pop() ; S // A.div(B) -W['/'] = VM(DIV) +W['/'] = CMD(DIV) def MOD(): B = S.pop() ; A = S.pop() ; S // A.mod(B) -W['%'] = VM(MOD) +W['%'] = CMD(MOD) def NEG(): B = S.pop() ; A = S.pop() ; S // A.neg() diff --git a/py/README b/py/README new file mode 100644 index 0000000..89d1c83 --- /dev/null +++ b/py/README @@ -0,0 +1 @@ +PyPy implementation for metaL core diff --git a/py/hello.py b/py/hello.py new file mode 100644 index 0000000..09495e9 --- /dev/null +++ b/py/hello.py @@ -0,0 +1,9 @@ +import sys + +def main(argv): + print 'hello' + +def target(*args): + return main,None + +if __name__ == '__main__': main(sys.argv) diff --git a/templates/firebase.html b/templates/firebase.html new file mode 100644 index 0000000..8da0afd --- /dev/null +++ b/templates/firebase.html @@ -0,0 +1,13 @@ + +