This week, I worked solely on the Prolog natural language parsing component of the project. This is basically a set of grammar rules along with very simple code-generation based on the results of the parse. I made quite a bit of progress this week… Basic movement commands are now parsed, along with quantities and conversions of a handful of different units. For example, you can now tell the Scribbler such things as:
* go forward for 3 seconds and then turn left
* drive forward three feet and then turn right 180 degrees
* move backwards 6.5 inches
And so on and so forth. Here is a sample run:
Enter a command: go forward two feet, turn right 90 degrees, drive backwards for three seconds
Prolog query executed: parseToCode([go,forward,two,feet,and,turn,right,90,degrees,and,drive,backwards,for,three,seconds], Status, CodeOut).
Status: valid
CodeOut: [‘forward(1.0, 4.1)’, ‘turnRight(1.0, 0.7875)’, ‘backward(1.0, 3)’]
A big component that I had to work on this week was english -> integer translation. It actually requires quite a bit of code to convert an English phrase like “nine hundred forty two point threee” to “942.3”!
My next task is to add some “fun” commands to the program; beeping, taking pictures, and maybe a wander/doodle capability. I would also like to add some flavorful error messages to return upon a failed parse.
Another potential goal is to add conditional statements to the parser, i.e. parsing of a statement like “go forward until you hit a wall and then turn left and take a picture.”
Here is the source code for the Prolog parser as it stands today…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | % Natural Language Parser for Scribbler II Robot % by Justin Mangue, 2013 % % References: % * "The Art of Prolog", Sterling & Shapiro, 1986. parse ToCode ( Sentence , Status , CodeListOut ) :- compound_sentence( ParseList , Sentence , []), Status = valid, generate_code_list( ParseList , [], CodeListOut ), !. parse ToCode ( Sentence , Status , CodeOut ) :- command_phrase( Parse , Sentence , []), Status = valid, generate_code_list([ Parse ], [], CodeOut ), !. parse ToCode ( Sentence , Status , CodeOut ) :- + command_phrase(_, Sentence , []), Status = invalid_sentence, CodeOut = 'null' , !. generate_code_list([], CodeList , CodeList ). generate_code_list([H|T], CodeList , CodeListOut ) :- generate_code(H, CodeLineOut ), append( CodeList , [ CodeLineOut ], NewCodeList ), generate_code_list(T, NewCodeList , CodeListOut ). generate_code(move(forward,S), CodeOut ) :- string_to_atom( Keyword , forward), CodeOut = [ Keyword ,1.0,S], !. generate_code(move(backward,S), CodeOut ) :- string_to_atom( Keyword , backward), CodeOut = [ Keyword ,1.0,S], !. generate_code(turn(left,S), CodeOut ) :- string_to_atom( Keyword , turn Left ), CodeOut = [ Keyword ,1.0,S], !. generate_code(turn(right,S), CodeOut ) :- string_to_atom( Keyword , turn Right ), CodeOut = [ Keyword ,1.0,S], !. /* generate_code(pic( Mode ), CodeOut ) :- string_to_atom( Keyword , take Picture ), CodeOut = [[ Keyword , Mode ],, */ compound_sentence( Compound ) --> command_phrase( Command ), connective( and ), compound_sentence( Sentence ), { append([ Command ], [ Sentence ], Compound_NotFlat ) }, { flatten2( Compound_NotFlat , Compound ) }. compound_sentence( Simple ) --> command_phrase( Simple ). command_phrase(pic( "color" )) --> [take], [a], [picture]. command_phrase(move(D,S)) --> action(go), direction(D), [for], unit_to_seconds(S). command_phrase(move(D,S)) --> action(go), direction(D), unit_to_seconds(S). command_phrase(move(D,1.5)) --> action(go), direction(D). command_phrase(turn(D,S)) --> action(turn), direction(D), unit_to_seconds(S). command_phrase(turn(D,S)) --> action(turn), direction(D), { S is 90*(3.15 / 360) }. % 90 degrees by default unit_to_seconds(S) --> to_number(S), { + S = 1 }, [seconds] ; to_number(S), { S = 1 }, [second]. unit_to_seconds(S) --> to_number( Feet ), { + Feet = 1 }, { S is Feet * 2.05 }, [feet] ; to_number( Feet ), { Feet = 1 }, { S is 2.05 }, [foot]. unit_to_seconds(S) --> to_number( Inches ), { + Inches = 1 }, { S is Inches * (2.05 / 12) }, [inches] ; to_number( Inches ), { Inches = 1 }, { S is (2.05 / 12) }, [inch]. unit_to_seconds(S) --> to_number( Degrees ), { + Degrees = 1 }, { S is Degrees * (3.15 / 360) }, [degrees] ; to_number( Degrees ), { Degrees = 1 }, { S is (3.15 / 360) }, [degree]. action(go) --> [go]. action(go) --> [move]. action(go) --> [drive]. action(go) --> [roll]. action(turn) --> [turn]. action(turn) --> [rotate]. action(spin) --> [spin]. connective( and ) --> [ and ], [then]. connective( and ) --> [ and ]. connective( and ) --> [then]. direction(forward) --> [forward]. direction(forward) --> [forwards]. direction(forward) --> [ahead]. direction(backward) --> [backward]. direction(backward) --> [backwards]. direction(left) --> [left]. direction(left) --> [counter-clockwise]. direction(right) --> [right]. direction(right) --> [clockwise]. % English number recognition from 0.0 - 9999.9 to_number(N) --> num( N1 ), [point], digit( N2 ), { N is N1 + (0.1 * N2 ) }. to_number(N) --> num(N). num(0) --> [zero]. num(N) --> xxxx(N). num(N) --> xxx(N). num(N) --> xx(N). num(N) --> digit(N). num(N) --> [N], { number(N) }. xxxx(N) --> digit(D), [thousand], xxx( N1 ), { N is D*1000+ N1 }. xxx(N) --> digit(D), [hundred], rest_xxx( N1 ), { N is D*100+ N1 }. rest_xxx(0) --> []. rest_xxx(N) --> [ and ], xx(N). rest_xxx(N) --> xx(N). xx(N) --> digit(N). xx(N) --> teen(N). xx(N) --> tens(T), rest_xx( N1 ), { N is T+ N1 }. rest_xx(0) --> []. rest_xx(N) --> digit(N). digit(1) --> [one]. digit(2) --> [two]. digit(3) --> [three]. digit(4) --> [four]. digit(5) --> [five]. digit(6) --> [six]. digit(7) --> [seven]. digit(8) --> [eight]. digit(9) --> [nine]. teen(10) --> [ten]. teen(11) --> [eleven]. teen(12) --> [twelve]. teen(13) --> [thirteen]. teen(14) --> [fourteen]. teen(15) --> [fifteen]. teen(16) --> [sixteen]. teen(17) --> [seventeen]. teen(18) --> [eighteen]. teen(19) --> [nineteen]. tens(20) --> [twenty]. tens(30) --> [thirty]. tens(40) --> [forty]. tens(50) --> [fifty]. tens(60) --> [sixty]. tens(70) --> [seventy]. tens(80) --> [eighty]. tens(90) --> [ninety]. sublist(S, L) :- append(_, L2 , L), append(S, _, L2 ). flatten2([], []) :- !. flatten2([L| Ls ], FlatL ) :- !, flatten2(L, NewL ), flatten2( Ls , NewLs ), append( NewL , NewLs , FlatL ). flatten2(L, [L]). |