.. index:: single: 言語設計; はじめに ======== 言語設計 ======== 言語設計の背景にある基本概念を学びます。 .. index:: pair: 言語設計; Ring を選ぶ理由は? Ring を選ぶ理由は? =================== プログラミング言語 Ring には簡明、違和感の排除、組織化の奨励、 および透過性とビジュアル実装があります。 簡潔なシンタックス、そして自然なインタフェースの作成を可能にする機能群、 短時間で作成・構築できる宣言型ドメイン特化言語機能を標準装備しています。 非常に小規模、高速なスマートガベージコレクターにより、 プログラマはメモリを制御下に置くことができます。 また、多種多様なプログラミングパラダイムに対応しており、便利で実用的なライブラリが付属しています。 Ring は生産性と拡張性に優れた高品質な解決方法の開発のために設計しました。 .. index:: pair: 言語設計; 明確な設計目標 明確な設計目標 ============== * アプリケーション開発用のプログラミング言語です。 * ドメイン特化ライブラリ、フレームワーク、およびツールを作成できる汎用プログラミング言語です。 * ビジュアル・プログラミング言語 Programming Without Coding Technology (PWCT) ソフトウェアの次世代版の開発用に設計した実用プログラミング言語です。 * 小規模・高速な言語で C/C++ プロジェクトへ組み込めます。 * 学習と入門 (文教用途、およびコンパイラ・仮想計算機の概念) に使用できる単純明快な言語です。 * 生産性と拡張性に優れた高品質な解決方法の開発。 .. index:: pair: 言語設計; 簡明 簡明 ==== Ring は非常に簡明な言語であり、非常に単純明快なシンタックスで構成しています。プログラマには、ボイラープレートコードのないプログラムの記述を奨励しています。 'See' 命令はメッセージを標準出力へ表示します。 .. code-block:: ring See "Hello, World!" Main 関数はオプション扱いであり、ステートメントの後に実行するため、ローカルスコープで便利です。 .. code-block:: ring Func Main See "Hello, World!" 動的型付け、およびレキシカルスコープを使用しています。変数名の先頭に $ は不要です! 文字列の連結は‘+’演算子です。弱い型付け言語であり、文字列はコンテキストに基づいて数値と文字列との間で自動的に変換します。 .. code-block:: ring nCount = 10 # グローバル変数 Func Main nID = 1 # ローカル変数 See "Count = " + nCount + nl + " ID = " + nID .. index:: pair: 言語設計; 違和感の排除 違和感の排除 ============ Ring は英数大小文字を区別しません。 .. code-block:: ring See "Enter your name ? " Give name See "Hello " + Name # Name は name と同じです。 リストのインデックス (添字番号) は 1 から開始します。 .. code-block:: ring aList = ["one","two","three"] See aList[1] # one を表示 定義前の関数呼び出し: .. code-block:: ring one() two() three() Func one See "One" + nl Func two See "two" + nl Func three See "three" + nl 代入演算子は深いコピーを使用します (この操作は参照ではありません)。 .. code-block:: ring aList = ["one","two","three"] aList2 = aList aList[1] = 1 see alist[1] # 1 を表示 see aList2[1] # one を表示 数値と文字列は値渡しですが、リストとオブジェクトは参照渡しです。 For in ループ でリストの項目 (アイテム、要素とも言います) を更新できます。 .. code-block:: ring Func Main aList = [1,2,3] update(aList) see aList # one two three を表示 Func update aList for x in aList switch x on 1 x = "one" on 2 x = "two" on 3 x = "three" off next 定義時のリスト使用: .. code-block:: ring aList = [ [1,2,3,4,5] , aList[1] , aList[1] ] see aList # 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 を表示 一階層以上のループから脱出 .. code-block:: ring for x = 1 to 10 for y = 1 to 10 see "x=" + x + " y=" + y + nl if x = 3 and y = 5 exit 2 # 二階層のループから脱出 ok next next .. index:: pair: 言語設計; 組織化の奨励 組織化の奨励 ============ Ring ではプログラムの組織化を奨励しています。まずは関数、次にクラス、 そして、関数とヘンテコなモノと組み合わせるプログラミング言語を使用していた悪夢の日々を忘却の彼方へ追いやります! ソースファイルの構造は: * ファイルの読み込み * ステートメントとグローバル変数 * 関数 * パッケージとクラス これにより、構成要素で end キーワードを記述しなくてもパッケージ、 クラスと関数を使えます。 一行コメント、または複数行コメントを使えます。 一行コメントは # あるいは // で始まります。 複数行コメントは /* ~ \*/ の間に記述します。 .. code-block:: ring /* プログラムの名前 : はじめての Ring プログラム 日付 : 2015.05.08 */ See "What is your name? " # 画面へメッセージを表示 give cName # ユーザからの標準入力を取得 see "Hello " + cName # こんにちわ! // See "Bye!" .. index:: pair: 言語設計; 簡潔なシンタックス 簡潔なシンタックス ================== 行の区別はしませんので、ステートメントの後に ; は不要です。または ENTER や TAB の打鍵は不要ですので、このようなコードを記述可能です。 .. code-block:: ring See "The First Message" See " Another message in the same line! " + nl See "Enter your name?" Give Name See "Hello " + Name このコードは三種類の属性 X, Y および Z を有する Point クラスを作成します。クラス、パッケージ、関数の定義を終了するために end キーワードは使用していません。また、クラス名の直下に属性名を書くことができます。 .. code-block:: ring Class Point X Y Z 定義前にクラスと関数を使えます。 この用例では、オブジェクトの新規作成と属性の設定、および値を表示します。 .. code-block:: ring o1 = New point o1.x=10 o1.y=20 o1.z=30 See O1 Class Point X Y Z ドット演算子‘.’でオブジェクトの属性とメソッドへアクセスするのではなく、括弧 { } でオブジェクトへアクセスできます。その後にオブジェクトの属性とメソッドを使えます。 .. code-block:: ring o1 = New point { x=10 y=20 z=30 } See O1 Class Point X Y Z メソッドの呼び出し後に { } でオブジェクトへアクセスします。 .. code-block:: ring oPerson = new Person { Name = "Somebody" Address = "Somewhere" Phone = "0000000" Print() # ここでは Print() メソッドを呼び出します。 } Class Person Name Address Phone Func Print See "Name :" + name + nl + "Address :" + Address + nl + "Phone : " + phone + nl { } で、オブジェクトへアクセスしてからオブジェクト名を記述するとき、自動的に呼び出される全ての setter/getter メソッドに対してクラスを検査します。 .. code-block:: ring New Number { See one # GetOne() の実行 See two # GetTwo() の実行 See three # GetThree() の実行 } Class Number one two three Func GetOne See "Number : One" + nl return 1 Func GetTwo See "Number : Two" + nl return 2 Func GetThree See "Number : Three" + nl return 3 .. index:: pair: 言語設計; 自然言語ステートメントの定義 自然言語ステートメントの定義 ============================ { } でオブジェクトへアクセス後に、クラスに BraceEnd() メソッドがあれば BraceEnd() メソッドを実行します! .. code-block:: ring TimeForFun = new journey # あっと驚く! TimeForFun { Hello it is me # なんと美しいプログラミングの世界でしょう! } # クラス本体 Class journey hello=0 it=0 is=0 me=0 func GetHello See "Hello" + nl func braceEnd See "Goodbye!" + nl Eval() 関数は、文字列に記述されたコードを実行します。 .. code-block:: ring cCode = "See 'Code that will be executed later!' " Eval(cCode) # コードを実行してメッセージを表示します。 リストの作成後に、実行用のコードをリストから生成できます。 .. code-block:: ring aWords = ["hello","it","is","me"] for word in aWords cCode=word+"=0" eval(cCode) next Read(cFileName) 関数は、テキストファイルを読み取ります。また Write(cFileName,cString) 関数はファイルへ書き込みます。 .. code-block:: ring See "Enter File Name:" Give cFileName See Read(cFileName) # ファイルの内容を表示 この用例は、二つの命令を定義するクラスの作成方法です。 * 最初の命令は : I want window * 次の命令は : Window title = <式> * ‘the’キーワードなどは無視されます。 .. code-block:: ring New App { I want window The window title = "hello world" } Class App # I want window 命令の属性 i want window nIwantwindow = 0 # Window title 命令の属性 # ここでは window 属性を再定義しません。 title nWindowTitle = 0 # 値を与えると、キーワードを無視します。 the=0 func geti if nIwantwindow = 0 nIwantwindow++ ok func getwant if nIwantwindow = 1 nIwantwindow++ ok func getwindow if nIwantwindow = 2 nIwantwindow= 0 see "Instruction : I want window" + nl ok if nWindowTitle = 0 nWindowTitle++ ok func settitle cValue if nWindowTitle = 1 nWindowTitle=0 see "Instruction : Window Title = " + cValue + nl ok 前述の用例を完了するには read() でファイルの内容を取得します。 .. code-block:: ring I want window The window title = "hello world" そして eval() でファイルの内容を実行します! また、 GUI ライブラリでウィンドウを作成するには GetWindow() と SetTitle() メソッドを更新します。 .. index:: pair: 言語設計; 宣言型言語の定義 宣言型言語の定義 ================ 自然言語ステートメントによるコードの実行、および入れ子構造によるコードの実行方法について既に学んでいます。 この用例は Web ライブラリからの引用です。 Bootstrap ライブラリで HTML ドキュメントを生成します。 この用例では、 HTML コードを直接記述せずに、類似言語を作成しています (ただの用例です)。その後、宣言型言語を使用するために入れ子構造で HTML ドキュメントを生成しています。この用例での考えかたとして GetDiv() および GetH1() メソッドは { } でアクセスできるオブジェクトを返します。各オブジェクトへのアクセス後に BraceEnd() メソッドが実行されると、生成された HTML を BraceEnd() の出力表示がルートに到達するまで親オブジェクトへ送信します。 .. code-block:: ring Load "weblib.ring" Import System.Web Func Main BootStrapWebPage() { div { classname = :container div { classname = :jumbotron H1 { text("Bootstrap Page") } } div { classname = :row for x = 1 to 3 div { classname = "col-sm-4" H3 { html("Welcome to the Ring programming language") } P { html("Using a scripting language is very fun!") } } next } } } このようなクラスで宣言型インタフェースを強化します。 .. code-block:: ring Class Link from ObjsBase title link Func braceend cOutput = nl+GetTabs() + " "+ Title + " " + nl Class Div from ObjsBase Func braceend cOutput += nl+'" + nl cOutput = TabMLString(cOutput) .. index:: pair: 言語設計; 柔軟性のあるシンタックス 柔軟性のあるシンタックス ======================== 様々なソースコードの記法があります! また、言語のキーワードと演算子を変更することで、お好みの記法を作成できます! .. index:: pair: 言語設計; 透過型実装 透過型実装 ========== Ring は透過型実装です。 コンパイラの処理段階、および仮想計算機による実行中の処理内容を把握できます。 例えば : ring helloworld.ring -tokens -rules -ic .. code-block:: ring See "Hello, World!" 実行結果 .. code-block:: ring ================================================================== Tokens - Generated by the Scanner ================================================================== Keyword : SEE Literal : Hello, World! EndLine ================================================================== ================================================================== Grammar Rules Used by The Parser ================================================================== Rule : Program --> {Statement} Line 1 Rule : Factor --> Literal Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> 'See' Expr ================================================================== ================================================================== Byte Code - Before Execution by the VM ================================================================== PC OPCode Data 1 FuncExE 2 PushC Hello, World! 3 Print 4 ReturnNull ================================================================== Hello, World! .. index:: pair: 言語設計; ビジュアル実装 ビジュアル実装 ============== Ring は、ビジュアル・プログラミングツール Programming Without Coding Technology (PWCT) で設計しました。 Ring のビジュアルソースは、 “visualsrc” フォルダの \*.ssf ファイルにあります。 生成された C 言語ソースコードは src フォルダ、 および include フォルダにあります。 このスクリーンショットは、 ring_vm.ssf ファイルからの引用です (ring_vm.c および ring_vm.h が生成されます)。 .. image:: visualsrc1.jpg このスクリーンショットは、 ring_list.ssf ファイルからの引用です (ring_list.c および ring_list.h が生成されます)。 .. image:: visualsrc2.jpg .. index:: pair: 言語設計; スマートガベージコレクター スマートガベージコレクター ========================== わずらわしいメモリ操作関連の問題から解放します。 * メモリへの不正アクセス * メモリリーク * 未初期化メモリへのアクセス * ダングリングポインタ 規則: * グローバル変数は、代入ステートメントで削除するまでメモリに存在し続けます。 * 関数の処理終了後に、ローカル変数を削除します。 * プログラマは、代入ステートメントでメモリから変数を削除する時期を完全に制御できます。 用例: .. code-block:: ring aList = [1,2,3,4,5] aList = "nice" 二行目の直後、リスト [1,2,3,4,5] はメモリから削除され、文字列 “nice” が残ります。 * プログラマは callgc() 関数を呼び出すことで、ガベージコレクターを強制実行できます。 * 変数参照時 (関数へオブジェクト、およびリストを渡すとき)、参照カウントに基づいて変数を削除します。未参照では全て削除されますが、参照しているときはデータはメモリに残ります。 .. index:: pair: 言語設計; インタプリタ (VM) 全体の停止なし (GIL なし) インタプリタ (VM) 全体の停止なし (GIL なし) =========================================== アプリケーションでスレッドを使うとき、インタプリタ (VM) 全体の停止 (global interpreter (VM) lock) は起こりません (GIL なし)。 よって、スレッドは並列動作可能であり、Ring 命令は同時実行されます。 これは、スレッドと平行性において最良のものです (さらなる高速化が実現できます!) .. index:: pair: 言語設計; ほとんどのアプリケーションで十分に高速動作します ほとんどのアプリケーションで十分に高速動作します ================================================ プログラミング言語 Ring は単純明快、小規模、柔軟性のある最先端の設計です。また、ほとんどのアプリケーションで十分に高速動作します。 これまで、市販の電子計算機で Ring を使用してきました。下記の処理は約1秒で完了します。 (1) 100,000 行コードのコンパイル (2) 1 ~ 10,000,000 まで数え上げる空ループの実行 (3) 100,000 項目から成るリストで最後の項目を見つけようとして、線形検索で 1000 回の検索処理を実行 (最悪値) (4) 1,000,000 項目から成るリストを作成後にリスト全項目の合計を計算 (5) GUI アプリケーションで ListWidget へ 20,000 アイテムを追加 (6) GUI アプリケーションで TreeWidget へ 5,000 ノードを追加 (7) ターミナルのコンソールアプリケーションで 10,000 メッセージを表示 さらなる高速化を求めるならば C/C++ 拡張機能を使えます! 用例: .. code-block:: ring ? "Create list contains 100,000 items" aList = 1:100000 ? "Do 1000 search operation - Find the last item (Worst Case!)" c = clock() for t = 1 to 1000 find(alist,100000) next ? "Time: " + ( clock() - c ) / clockspersecond() + " seconds" 実行結果: .. code-block:: none Create list contains 100,000 items Do 1000 search operation - Find the last item (Worst Case!) Time: 0.87 seconds 用例: .. code-block:: ring load "guilib.ring" func main new qApp { win = new qWidget() { move(100,100) resize(500,500) setWindowTitle("Many Tree Items - Testing Performance") tree = new qTreeWidget(win) { blocksignals(True) setUpdatesEnabled(False) root = new qTreeWidgetItem() root.setText(0,"The Root Node") t1 = clock() for t = 1 to 5000 oItem = new qTreeWidgetItem() oItem.settext(0,"Item " + t) root.addchild(oItem) next cTime = (clock()-t1)/clockspersecond() setHeaderLabel("Creating 5000 nodes in " + cTime + " seconds.") addTopLevelItem(root) expanditem(root) blocksignals(False) setUpdatesEnabled(True) } oLayout = new qVBoxLayout() { addWidget(tree) } setLayout(oLayout) show() } exec() } 実行結果: .. image:: manytreeitems.png :alt: 大量のツリー項目