diff --git a/p.typ b/p.typ new file mode 100644 index 0000000..46e3ba6 --- /dev/null +++ b/p.typ @@ -0,0 +1,1062 @@ +# GNU Typist - improved typing tutor program for UNIX systems +# Copyright (C) 1998 Simon Baldwin (simonb@sco.com) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This lesson was written by Daniel Long Sockwell + + +# The main menu +*:MENU +B:Special characters course +M: "The P series contains the following 11 lessons" + :SPECIAL_NUMS_REVIEW "Lesson P1 Review ! @ # $ % ^ & * ( ) _" + :OTHER_PRIOR_SPECIAL_CHAR "Lesson P2 Review ? / " ' :" + :PLUS_EQUAL "Lesson P3 + - _ =" + :ANGLE_BRACKETS "Lesson P4 > <" + :BRACES "Lesson P5 } {" + :SQUARE_BRACKETS "Lesson P6 ] [" + :BACKTICK "Lesson P7 ` ~" + :PIPE "Lesson P8 \ |" + :PRACTICE_1 "Lesson P9 Practice 1" + :PRACTICE_2 "Lesson P10 Practice 2" + :PRACTICE_3 "Lesson P11 Practice 3" + + +# Lesson P1—Special Characters Review +*:SPECIAL_NUMS_REVIEW +B:Lesson P1 +T:In the P series of lessons we work on special characters with an + :emphasis on characters that are used when writing code in programming + :or markup languages. + : + :We will start by reviewing the special characters that share keys with + :the numerals on a standard US QWERTY keyboard: ! @ # $ % ^ & * ( ). If + :you would like additional practice with these keys, please refer to the + :T series of lessons in Gtypist. + +I:(1) Warm up +D:The quick brown fox jumps over the lazy dog. + :The sum of 1 and 2 is 3; the product of 6 and 9 is 54. + +I:(2) Type the ! @ # $ % and ^ keys with your left hand +D:!!!! @@@@ #### $$$$ %%%% ^^^^ + :!@#$ #$%^ !!^^ %^%^ $$%% ##@! + :^!%@ ##%% %$%$ @@^^ ##!! ^!$# + +I:(3) Type the & * ( and ) keys with your right hand +D:&&&& **** (((( )))) &*() )(*& + :(()) &&** *&*& (&&) (**) (()) + +I:(4) Practice with these characters +D:)!(@ #*$& %^%^ @@)) $$&& *$*$ + :(@@) ##)( %^%^ !#*& )!)! @*@* + +I:(5) Try some sentences +S:It is hard to believe, but 230 minus 220 times one half equals 5! + :(And 5!, of course, equals 5 * 4 * 3 * 2 * 1.) + : + :username@domainname.com is the #1 most common format for email addresses. + :To convey Three Squared in numerals, some people write 3^2. But in some + :programming languages, you should write 3 ** 2 instead. + :The % symbol can have different meanings; it can mean percent, as in + :(10% of 90) equals 9 + :or it can mean modulo, as in + :10 % 9 equals 1 + : + :The HTML entity for the & symbol is &. + +I:(6) And try our first bit of code +S:# Hello world in Python 2 + :print "Hello World!" + : + : + :# Hello world in Python 3 + :print("Hello world!") + : + : + :# Hello world in Ruby + :puts "Hello World!" + : + : + :;;; Hello world in Emacs Lisp + :(defun hello-world() + : "Display the string hello world." + : (interactive) + : (message "Hello World!")) + : + : + :" Hello world in Vim script + ::echom "Hello World!" + : + : + :# Hello world in SQL + :SELECT 'Hello World!'; + : + : + :% Hello world in MATLAB + :disp('Hello World!'); +Q:Do you want to continue to lesson P2 [Y/N] ? +N:MENU + + +# Lesson P@—Special Characters Review, Pt 2 +*:OTHER_PRIOR_SPECIAL_CHAR +B:Lesson P2 +I:(1) Warm up/review +D:The! quick@ brown# fox$ jumps% over^ the& lazy* dog() + :Buy 5 #2 pencils @ $0.99 each, but ask for a 15% discount for being a *friend* + +I:(2) Hit the / and ? keys with the ; finger +D:;;;; //// ;;// ;/;/ //;; /;/; + :;;;; ???? ;;?? ;?;? ??;; ?;?; + :;;;; /?/? ;;/? ;/;? ?/;; ?;/; + +I:(3) Hit the ' " and : keys with the ; finger +D:;;;; '''' ;;'' ;';' '';; ';'; + :;;;; :::: ;;:: ;:;: ::;; :;:; + :;;;; """" ;;"" ;";" "";; ";"; + :;;;; :'"; "':; ";;" '::' :"": + +I:(4) Practice these characters +D:;;;; /'?" "??" '//' ";;" '??' + :;;?? "";; ::;; '':: '//' :"": + +I:(5) Try some more sentences +S:What is your name? I hope it's "Bob": I've always liked the name "Bob". + : + :I've noticed that few gadgets have "on/off" switches these days. These days, + :it's all "on/standby" or something! Why is that? Is "off" not good enough? + +I:(6) And now a bit more "Hello world" coding +S:// Hello world in JavaScript + :console.log("Hello World!"); + : + : + :// Hello world in Swift + :println("Hello, World!") + : + : + :# Hello world in Lua + :print "Hello World!" + : + : + :# Hello world in Perl 6 + :say 'Hello World!'; + : + : + :// Hello world in TypeScript + :alert('Hello World!'); + : + : + :'Hello world in Visual Basic .NET + :Imports System.Console + : + :Class HelloWorld + : + : Public Shared Sub Main() + : WriteLine("Hello, world!") + : End Sub + : + :End Class + +Q:Do you want to continue to lesson P3 [Y/N] ? +N:MENU + + +# Lesson P3—Plus and Equal +*:PLUS_EQUAL +B:Lesson P3 +I:(1) Warm up/review +D:The five boxing wizards jump quickly. + :How vexingly quickly daft zebras jump! + :?!/* "%^" $;#* ##)( @@^) :??: + +I:(2) Hit the - and _ keys with the ; finger +D:;;;; ---- ;;-- ;-;- --;; -;-; + :;;;; ____ ;;__ ;_;_ __;; _;_; + :;-;- ;;__ __-- -_;; ;_-; -;;_ + +I:(3) Hit the + and + keys with the ; finger +D:;;;; ==== ;;== ;=;= ==;; =;=; + :;;;; ++++ ;;++ ;+;+ ++;; +;+; + :;=;= ;;++ ++== =+;; ;+=; =;;+ + +I:(4) Practice these characters +D:==++ --__ +--+ +_=- _=+- + :--__ =_=_ ++__ -=_+ __++ + +I:(5) Practice these characters with other ;-finger characters +D:'__' +/-= "--" ::++ ?__? + :;:;: -+-+ /++/ -_-_ ??++ + +I:(6) Try some sentences +S:The hyphen ("-") is used for compound words; the en dash, + :which is longer than a hyphen, is used to indicate a range. + :If you cannot use a true en dash, some people accept two + :hyphens ("--") instead. The em dash is even longer than an + :en dash, and is used to indicate a break in a sentence. If + :you cannot use a true em dash, some people accept three + :hyphens ("---") instead. + : + :If you cannot emphasize text by setting it in italic or by + :underlining it, you can show emphasis with underscores ("like + :_this_"). + +I:(7) And some programming/math +S:int first_number = 7; + :int second_number = 40; + :int third_number = first_number + second_number - first_number; + : + : + :1 + 2 + 8 + 12 - 74 = -51 + : + : + :for (let i = 0; i !== arr.length; i++) + : + :let a = 'string'; + :let b = 'string'; + :if (a === b) console.log('"a" and "b" are equal'); + : + : + :if ((10 / 10) === 5 % 4) console.log('Yep, that is how math works'); + +Q:Do you want to continue to lesson P4 [Y/N] ? +N:MENU + + +# Lesson P4—Angle Brackets +*:ANGLE_BRACKETS +B:Lesson P4 +I:(1) Warm up/review +D:Glib jocks quiz nymph to vex dwarf. + :Sphinx of black quartz, judge my vow! + :Two driven jocks help fax my big quiz. + +I:(2) Hit the < key with your k finger +D:kkkk <<<< kk<< ,,<< ,k key with your l finger +D:llll >>>> ll>> ..>> .l>L L..L >ll> + :llll >>.. .>>. l>>l >LL> .l>L .>l> + +I:(4) Practice these characters +D:<<>> K<>L >kl< + :<..> <,,> <.,> ><>< <<>> + +I:(5) Try some quick sentences +S:Five is > two but < six. + :If your age isn't >= 21, you cannot drink in most of the United States. + :If your vision is < 20/200, then you are legally blind in the United States. + +I:(6) Write some HTML markup +S: + : + : + : + : Example_Title + : + : + : + : + : + : + : + :
+ : + :

Example

+ :
+ : + :
+ : + :
+ : + : + : + :
+ : + :
+ : + : + : +Q:Do you want to continue to lesson P5 [Y/N] ? +N:MENU + + +# Lesson P5—Curly Braces +*:BRACES +B:Lesson P5 +I:(1) Warm up +D:Five quacking zephyrs jolt my wax bed. + :Pack my box with five dozen liquor jugs. + :Few quips galvanized the mock jury box. + +I:(2) Hit the { key with the ; finger +D:;;;; {{{{ ;;{{ ;{{; {;{; {{;; + :;;;; {{{{ ;{;{ {;;{ ;{;{ ;;{{ + +I:(3) Hit the } key with the ; finger +D:;;;; }}}} ;;}} ;}}; };}; }};; + :;;;; }}}} ;};} };;} ;};} ;;}} + +I:(4) Practice these characters together +D:{{}} }}{{ ;;;; {{{{ }}}} }};; + :{{:: "{}" {00} {ll} }}{{ :{}: + +I:(5) Try some coding +S:/* Hello world in C, K&R style */ + :main() + :{ + : puts("Hello world!"); + : return 0; + :} + : + :// Hello world in C++ + :#include + : + :main() + :{ + : cout << "Hello World!" << endl; + : return 0; + :} + : + : + :// Hello world in C# + :class HelloWorld + :{ + : static void Main() + : { + : System.Console.WriteLine("Hello, World!"); + : } + :} + : + : + : + : + : + :// Hello world in Delphi + :Program Hello_World; + : + :{$APPTYPE CONSOLE} + : + :Begin + : WriteLn('Hello World'); + :End. + +Q:Do you want to continue to lesson P7 [Y/N] ? +N:MENU + + +# Lesson P6—Square Brackets +*:SQUARE_BRACKETS +B:Lesson P6 + +I:(1) Review +D:;;;; ;';' ;p;p ;-;- ;";" ;/;/ ;?;? ;:;: ;_;_ + :;;PP ;p-/ :;:; ;;;; _P?p "PP" p-p; P/P? --?? +I:(2) Use your ;-finger for the [-key +D:;;;; [[[[ ;[;[ ;;[[ [[;; [;[; + :[[[[ [;[; ['[' [p[p [-[- [/[/ + :[[[[ [:[: ["[" [P[P [_[_ [?[? +I:(3) Use your ;-finger for the ]-key +D:;;;; ]]]] ;];] ;;]] ]];; ];]; + :]]]] ];]; ]']' ]p]p ]-]- ]/]/ + :]]]] ]:]: ]"]" ]P]P ]_]_ ]?]? +I:(4) Practice the ] and [ keys +D:;[]; ];[; ;;][ ];;[ [];; ][;; + :[;'] [p-] [-/] [:"] [P_] [_?] +I:(5) Try some sentences +S:Hello [name]! How are you this [time_of_day]? + : + :I'm [current_feeling], thanks for asking. Are you also [current_feeling]? + : + :And how about [spouse]? [Is he/Is she/Are they] doing well? + : + :How about those [local_sports_team], eh? +I:(6) The [- and ]-keys are frequently used when working with arrays +S:int array[10]; + :int array_one[]; + :double array_two[]; + :int array_three[ 20 ]; + : + :// a multidimensional array in JavaScript + :let arr = [ + : [A1, A2, A3, A4, A5], + : [B1, B2, B3, B4, B5], + : [C1, C2, C3, C4, C5], + : [D1, D2, D3, D4, D5], + : [E1, E2, E3, E4, E5], + :]; + + +Q:Do you want to continue to lesson P7 [Y/N] ? +N:MENU + + +# Lesson P7—Backtick +*:BACKTICK +B:Lesson P7 +I:(1) Review +D:}]}] {{}} [[]] "[]" ;;{{ ??}} ;;'' + :--++ [++] {==} '??' //;; :--: {__} + +I:(2) Press the ` key with the a finger +D:aaaa ```` aa`` ``aa `aa` a``a + :qq`` `qq` ``11 z``a `qq` `zz` + +I:(3) Press the ~ key with the a finger +D:aaaa ~~~~ aa~~ ~~aa ~aa~ a~~a + :qq~~ ~qq~ ~~11 z~~a ~qq~ ~zz~ + +I:(4) Practice the ~ and ` keys +D:~~`` `~~` `!!` ``QQ zz`` ~~11 + :``~~ ~``~ ~!!~ ~~ZZ qq~~ ``11 + :`~~` `ZZ` QQ~~ aa~~ `11` ~!!~ + +I:(5) Try some terminal commands +S:cd ~/Documents + :cp ~/Documents/resume.txt ~/Documents/resume.txt.bk + :mv ~/Documents/resume.md ~/Documents/resume.html + :rm ~/Documents/resume.md + +I:(6) Try some programing with template literals +S:let greeting = 'Hello'; + :console.log(`${greeting}, world`); + : + :`${variable}` + : + :`Hello, ${name}, how are you?` + : + :console.log(`string text line 1 + :string text line 2`); + : + :var a = 5; + :var b = 10; + :console.log(`Fifteen is ${a + b} and + :not ${2 * (a + b)}`); + : + :const classes = `header ${ isLargeScreen() ? '' : + : `icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`; + : + :sudo chown `id -u` /somedir + + +Q:Do you want to continue to lesson P8 [Y/N] ? +N:MENU + + +# Lesson P8—Pipe +*:PIPE +B:Lesson P8 +I:(1) Review +D:2030 5946 1411 4062 8077 8786 2534 9640 + :@)#) %($^ !$!! $)^@ *)&& *&*^ @%#$ (^$) + : + :<;;> "//" {''} [+-] `qq` ({[< >]}) -_~~ + +I:(2) Use your ; finger for the \ key +D:\\\\ ;;;; \\;; \\]] [[\\ {{\\ + :\}}\ "\\" ;;\\ //\\ ?\\? :\\: + :\\\\ ++\\ \__\ \\// \==\ \pp\ + +I:(3) Use your ; finger for the | key +D:|||| ;;;; ||;; ||]] [[|| {{|| + :|}}| "||" ;;|| //|| ?||? :||: + :|||| ++|| |__| ||// |==| |pp| + +I:(4) Practice these characters together +D:\\\\ |||| ||\\ \\|| |\\| \||\ + :"||" '\\' {||} [\\] ??|| \|\| + +I:(5) Try some terminal commands +S:ls | more + :ls /usr/bin | less + :ls *.jpg | xargs -n1 -i cp {} /external-hard-drive/directory + : + :sed '/./=' filename.txt | sed 'N; s/\n/ /' + :sort -t: -k 3n /etc/passwd | more + :find / -name *.jpg -type f -print | xargs tar -cvzf images.tar.gz + :cat url-list.txt | xargs wget -c + : + :ps -ef | more + :ps -efH | more + :ps -ef | grep chrome + + +I:(6) Try some writing some regular expressions +S:// match a valid phone number + :/^\(*\d{3}\)*( |-)*\d{3}( |-)*\d{4}$/ + : + :// match a hexadecimal number + :/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/ + : + :// match an email + :/^(A-Za-z0-9_\.-]+)@([A-Za-z0-9_\.-]+)\.([A-Za-z\.]{2,6})$/ + : + :// match a URL + :/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/ + : + :// match an IP address + :/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2 + :[0-4][0-9]|[01]?[0-9][0-9]?)$/ + : + :// match an HTML tag + :/^<([A-Za-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$/ + +Q:Do you want to continue to lesson P9 [Y/N] ? +N:MENU + + +# Lesson P9—Practice with Simple Programs +*:PRACTICE_1 +B:Lesson P9 +I:(1) Practice with simple programs. Try a palindrome finder in Python +S:# function to check string is + :# palindrome or not + :def isPalindrome(str): + : for i in xrange(0, len(str)/2): + : if str[i] != str[len(str)-i-1]: + : return False + : return True + +I:(2) Try the same code in JavaScript +S:// function to check if a string is a palindrome + :function isPalindrome(str) { + : for (let i = 0; i < str.length; i += 1) { + : if (str[i] !== str[str.length - 1 - i]) { return false; } + : } + : return true; + :} + +I:(3) Try the same problem in C++ +S:bool IsPalindrome(const char* psz) + :{ + : int i = 0; + : int j; + : + : if ((psz == NULL) || (psz[0] == '\0')) + : { + : return false; + : } + : + : j = strlen(psz) - 1; + : while (i < j) + : { + : if (psz[i] != psz[j]) + : { + : return false; + : } + : i++; + : j--; + : } + : + : return true; + :} + +I:(4) Try the same problem in C, using functions and pointers (part 1) +S:#include + : + :int is_palindrome(char*); + :void copy_string(char*, char*); + :void reverse_string(char*); + :int string_length(char*); + :int compare_string(char*, char*); + : + :int main() + :{ + : char string[100]; + : int result; + : + : printf("Input a string\n"); + : gets(string); + : + : result = is_palindrome(string); + : + : if ( result == 1 ) + : printf("\"%s\" is a palindrome string.\n", string); + : else + : printf("\"%s\" isn't a palindrome string.\n", string); + : + : return 0; + :} + +I:(5) Try the same problem in C, continued +S:int is_palindrome(char *string) + :{ + : int check, length; + : char *reverse; + : + : length = string_length(string); + : reverse = (char*)malloc(length+1); + : + : copy_string(reverse, string); + : reverse_string(reverse); + : + : check = compare_string(string, reverse); + : + : free(reverse); + : + : if ( check == 0 ) + : return 1; + : else + : return 0; + :} + +I:(6) Try the same problem in C, continued +S:int string_length(char *string) + :{ + : int length = 0; + : + : while(*string) + : { + : length++; + : string++; + : } + : + : return length; + :} + : + :void copy_string(char *target, char *source) + :{ + : while(*source) + : { + : *target = *source; + : source++; + : target++; + : } + : *target = '\0'; + :} + +I:(7) Try the same problem in C, continued +S:void reverse_string(char *string) + :{ + : int length, c; + : char *begin, *end, temp; + : + : length = string_length(string); + : + : begin = string; + : end = string; + : + : for ( c = 0 ; c < ( length - 1 ) ; c++ ) + : end++; + : + : for ( c = 0 ; c < length/2 ; c++ ) + : { + : temp = *end; + : *end = *begin; + : *begin = temp; + : + : begin++; + : end--; + : } + :} + : + :int compare_string(char *first, char *second) + :{ + : while(*first==*second) + : { + : if ( *first == '\0' || *second == '\0' ) + : break; + : + : first++; + : second++; + : } + : if ( *first == '\0' && *second == '\0' ) + : return 0; + : else + : return -1; + :} + +Q:Do you want to continue to lesson P10 [Y/N] ? +N:MENU + + +# Lesson P10—Practice with Doug Lea's malloc +*:PRACTICE_2 +B:Lesson P10 +I:(1) Try this excerpt from Doug Lea's malloc, written in C +S:/* ------------------------ system deallocation -------------------------- */ + : + :/* Unmap and unlink any mmapped segments that don't contain used chunks */ + :static size_t release_unused_segments(mstate m) { + : size_t released = 0; + : int nsegs = 0; + : msegmentptr pred = &m->seg; + : msegmentptr sp = pred->next; + : while (sp != 0) { + : char* base = sp->base; + : size_t size = sp->size; + : msegmentptr next = sp->next; + : ++nsegs; + : if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { + : mchunkptr p = align_as_chunk(base); + : size_t psize = chunksize(p); + : /* Can unmap if first chunk holds entire segment and not pinned */ + : if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { + : tchunkptr tp = (tchunkptr)p; + : assert(segment_holds(sp, (char*)sp)); + : if (p == m->dv) { + : m->dv = 0; + : m->dvsize = 0; + : } + : else { + : unlink_large_chunk(m, tp); + : } + : if (CALL_MUNMAP(base, size) == 0) { + : released += size; + : m->footprint -= size; + : /* unlink obsoleted record */ + : sp = pred; + : sp->next = next; + : } + : else { /* back out if cannot unmap */ + : insert_large_chunk(m, tp, psize); + : } + : } + : } +I:(2) Doug Lea's malloc, continued +S: if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ + : break; + : pred = sp; + : sp = next; + : } + : /* Reset check counter */ + : m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)? + : (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE); + : return released; + :} + : + :static int sys_trim(mstate m, size_t pad) { + : size_t released = 0; + : ensure_initialization(); + : if (pad < MAX_REQUEST && is_initialized(m)) { + : pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + : + : if (m->topsize > pad) { + : /* Shrink top space in granularity-size units, keeping at least one */ + : size_t unit = mparams.granularity; + : size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + : SIZE_T_ONE) * unit; + : msegmentptr sp = segment_holding(m, (char*)m->top); + : + : if (!is_extern_segment(sp)) { + : if (is_mmapped_segment(sp)) { + : if (HAVE_MMAP && + : sp->size >= extra && + : !has_segment_link(m, sp)) { /* can't shrink if pinned */ + : size_t newsize = sp->size - extra; + : (void)newsize; /* placate people compiling -Wunused-variable */ + : /* Prefer mremap, fall back to munmap */ + : if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || + : (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + : released = extra; + : } + : } + : } +I:(3) Doug Lea's malloc, continued +S: else if (HAVE_MORECORE) { + : if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + : extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; + : ACQUIRE_MALLOC_GLOBAL_LOCK(); + : { + : /* Make sure end of memory is where we last set it. */ + : char* old_br = (char*)(CALL_MORECORE(0)); + : if (old_br == sp->base + sp->size) { + : char* rel_br = (char*)(CALL_MORECORE(-extra)); + : char* new_br = (char*)(CALL_MORECORE(0)); + : if (rel_br != CMFAIL && new_br < old_br) + : released = old_br - new_br; + : } + : } + : RELEASE_MALLOC_GLOBAL_LOCK(); + : } + : } + : + : if (released != 0) { + : sp->size -= released; + : m->footprint -= released; + : init_top(m, m->top, m->topsize - released); + : check_top_chunk(m, m->top); + : } + : } + : + : /* Unmap any unused mmapped segments */ + : if (HAVE_MMAP) + : released += release_unused_segments(m); + : + : /* On failure, disable autotrim to avoid repeated failed future calls */ + : if (released == 0 && m->topsize > m->trim_check) + : m->trim_check = MAX_SIZE_T; + : } + : + : return (released != 0) ? 1 : 0; + :} + +Q:Do you want to continue to lesson P11 [Y/N] ? +N:MENU + + +# Lesson P11—Practice with the Super Tiny Compiler +*:PRACTICE_3 +B:Lesson P11 — final lesson +I:(1) Type Jamie Kyle's Super Tiny Compiler (CC BY 4.0 License) +S:'use strict' + :function tokenizer(input) { + : let current = 0; + : let tokens = []; + : while (current < input.length) { + : let char = input[current]; + : if (char === '(') { + : tokens.push({ + : type: 'paren', + : value: '(', + : }); + : current++; + : continue; + : } + : if (char === ')') { + : tokens.push({ + : type: 'paren', + : value: ')', + : }); + : current++; + : continue; + : } + : let WHITESPACE = /\s/; + : if (WHITESPACE.test(char)) { + : current++; + : continue; + : } + : let NUMBERS = /[0-9]/; + : if (NUMBERS.test(char)) { + : let value = ''; + : while (NUMBERS.test(char)) { + : value += char; + : char = input[++current]; + : } + : tokens.push({ type: 'number', value }); + : continue; + : } +I:(2) Super Tiny Compiler, continued +S: if (char === '"') { + : let value = ''; + : char = input[++current]; + : while (char !== '"') { + : value += char; + : char = input[++current]; + : } + : char = input[++current]; + : tokens.push({ type: 'string', value }); + : continue; + : } + : let LETTERS = /[a-z]/i; + : if (LETTERS.test(char)) { + : let value = ''; + : while (LETTERS.test(char)) { + : value += char; + : char = input[++current]; + : } + : tokens.push({ type: 'name', value }); + : continue; + : } + : throw new TypeError('I dont know what this character is: ' + char); + : } + : return tokens; + :} + : + :function parser(tokens) { + : let current = 0; + : function walk() { + : let token = tokens[current]; + : if (token.type === 'number') { + : current++; + : return { + : type: 'NumberLiteral', + : value: token.value, + : }; + : } +I:(3) Super Tiny Compiler, continued +S: if (token.type === 'string') { + : current++; + : return { + : type: 'StringLiteral', + : value: token.value, + : }; + : } + : if ( + : token.type === 'paren' && + : token.value === '(' + : ) { + : token = tokens[++current]; + : let node = { + : type: 'CallExpression', + : name: token.value, + : params: [], + : }; + : token = tokens[++current]; + : while ( + : (token.type !== 'paren') || + : (token.type === 'paren' && token.value !== ')') + : ) { + : node.params.push(walk()); + : token = tokens[current]; + : } + : current++; + : return node; + : } + : throw new TypeError(token.type); + : } + : let ast = { + : type: 'Program', + : body: [], + : }; + : while (current < tokens.length) { + : ast.body.push(walk()); + : } + : return ast; + :} +I:(4) Super Tiny Compiler, continued +S:function traverser(ast, visitor) { + : function traverseArray(array, parent) { + : array.forEach(child => { + : traverseNode(child, parent); + : }); + : } + : function traverseNode(node, parent) { + : let methods = visitor[node.type]; + : if (methods && methods.enter) { + : methods.enter(node, parent); + : } + : switch (node.type) { + : case 'Program': + : traverseArray(node.body, node); + : break; + : case 'CallExpression': + : traverseArray(node.params, node); + : break; + : case 'NumberLiteral': + : case 'StringLiteral': + : break; + : default: + : throw new TypeError(node.type); + : } + : if (methods && methods.exit) { + : methods.exit(node, parent); + : } + : } + : traverseNode(ast, null); + :} +I:(5) Super Tiny Compiler, continued +S:function transformer(ast) { + : let newAst = { + : type: 'Program', + : body: [], + : }; + : ast._context = newAst.body; + : traverser(ast, { + : NumberLiteral: { + : enter(node, parent) { + : parent._context.push({ + : type: 'NumberLiteral', + : value: node.value, + : }); + : }, + : }, + : StringLiteral: { + : enter(node, parent) { + : parent._context.push({ + : type: 'StringLiteral', + : value: node.value, + : }); + : }, + : }, +I:(6) Super Tiny Compiler, continued +S: CallExpression: { + : enter(node, parent) { + : let expression = { + : type: 'CallExpression', + : callee: { + : type: 'Identifier', + : name: node.name, + : }, + : arguments: [], + : }; + : node._context = expression.arguments; + : if (parent.type !== 'CallExpression') { + : expression = { + : type: 'ExpressionStatement', + : expression: expression, + : }; + : } + : parent._context.push(expression); + : }, + : } + : }); + : return newAst; + :} +I:(7) Super Tiny Compiler, continued +S:function codeGenerator(node) { + : switch (node.type) { + : case 'Program': + : return node.body.map(codeGenerator) + : .join('\n'); + : case 'ExpressionStatement': + : return ( + : codeGenerator(node.expression) + + : ';' + : ); + : case 'CallExpression': + : return ( + : codeGenerator(node.callee) + + : '(' + + : node.arguments.map(codeGenerator) + : .join(', ') + + : ')' + : ); + : case 'Identifier': + : return node.name; + : case 'NumberLiteral': + : return node.value; + : case 'StringLiteral': + : return '"' + node.value + '"'; + : default: + : throw new TypeError(node.type); + : } + :} +I:(8) Super Tiny Compiler, continued +S:function compiler(input) { + : let tokens = tokenizer(input); + : let ast = parser(tokens); + : let newAst = transformer(ast); + : let output = codeGenerator(newAst); + : return output; + :} + : + :module.exports = { + : tokenizer, + : parser, + : traverser, + : transformer, + : codeGenerator, + : compiler, + :}; + +G:MENU