-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from vivz/develop
Good work guys!
- Loading branch information
Showing
21 changed files
with
1,094 additions
and
290 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,4 @@ | |
.DS_Store | ||
*pycache* | ||
*.pyc | ||
data/ | ||
*.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from django.core.management.base import BaseCommand, CommandError | ||
from LL1_Academy.models import Grammar | ||
|
||
class Command(BaseCommand): | ||
help = 'This will delete all grammars in the database be careful' | ||
|
||
def handle(self, *args, **options): | ||
Grammar.objects.all().delete() |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from django.core.management.base import BaseCommand, CommandError | ||
import time | ||
from LL1_Academy.tools import MassGrammarGenerator | ||
import os | ||
|
||
class Command(BaseCommand): | ||
help = 'This command will populate the database with a small set of grammars' | ||
|
||
def handle(self, *args, **options): | ||
#Number of randomly generated grammars | ||
num = 100 | ||
|
||
#Number variables this run will include. | ||
#For example [2,3] will run the script to generate | ||
#grammars with 2 variables and 3 variables | ||
nVariables = [2, 3] | ||
|
||
nonTerminals = ['A','B','C','D'] | ||
terminals = ['x','y','z','w'] | ||
|
||
for n in nVariables: | ||
start_time = time.time() | ||
mg = MassGrammarGenerator.MassGrammarGenerator(n) | ||
mg.run(num,nonTerminals[:n],terminals) | ||
print("{}Variables: {} seconds---".format(n,(time.time() - start_time))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,9 @@ | ||
{% extends "LL1_Academy/_base.html" %} | ||
{% block content %} | ||
<a href="learn"><button>Start Learning</button></a> | ||
<div id="landingPage"> | ||
<h1 id="siteTitle">LL(1) Academy</h1> | ||
<div id="startButton"> | ||
<a href="learn"><button class="button" id="startLearning">Start Learning</button></a> | ||
</div> | ||
</div> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,41 @@ | ||
from django.test import TestCase | ||
from django.test import TestCase, Client | ||
from django.urls import reverse | ||
from LL1_Academy.models import Grammar, Question | ||
|
||
|
||
class UrlTest(TestCase): | ||
def setup(self): | ||
g = Grammar(prods="{'A': ['xA', 'Bz'],'B': ['yB']}", nonTerminals="AB", terminals="xyz", startsymbol="A") | ||
g.save() | ||
q = Question(gid=g, qnum=0, category="FI", symbol="A", answer="xy") | ||
q.save() | ||
|
||
def test_index1(self): | ||
response = self.client.get('/') | ||
self.assertEqual(response.status_code, 200) | ||
|
||
def test_index2(self): | ||
response = self.client.get('/index') | ||
self.assertEqual(response.status_code, 200) | ||
|
||
def test_learn(self): | ||
response = self.client.get('/learn') | ||
self.assertEqual(response.status_code, 200) | ||
|
||
def test_get_question(self): | ||
response = self.client.get('/get_question') | ||
self.assertEqual(response.status_code, 200) | ||
|
||
def test_check_answer(self): | ||
response = self.client.get('/check_answer') | ||
self.assertEqual(response.status_code, 404) | ||
|
||
class RenderingTest(TestCase): | ||
def test_index1(self): | ||
response = self.client.get('/') | ||
self.assertTemplateUsed(response, 'LL1_Academy/index.html') | ||
|
||
def test_index1(self): | ||
response = self.client.get('/learn') | ||
self.assertTemplateUsed(response, 'LL1_Academy/learn.html') | ||
|
||
# Create your tests here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,101 @@ | ||
from LL1_Academy.tools import GrammarChecker,SingleGrammarGenerator | ||
from LL1_Academy.tools import GrammarChecker,SingleGrammarGenerator, SvmLearn | ||
from LL1_Academy.models import Grammar, Question | ||
import os | ||
|
||
# | ||
#Description: The MassGrammarGenerator class outputs a specified number of | ||
# random grammars based on the given list of terminals and non-terminals | ||
# | ||
#Input: num: the number of grammars to be generated | ||
# nonTerminals: a list of characters representing the nonterminals of length 2-4 | ||
# Terminals: a list of characters representing the terminals of length 2-4 | ||
# | ||
#Output: a specified number of grammars written to some plaintext files under ./txt. | ||
# You may need to create this directory first before running this script in order | ||
# for it to work. | ||
# | ||
#Usage: | ||
# mg = MassGrammarGenerator() | ||
# mg.run(1000,['S','F'],['a','(','+',')']) | ||
# | ||
#Description: The MassGrammarGenerator class randomly generates grammar and filter | ||
#out the interesting ones to store in the database. | ||
|
||
script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in | ||
|
||
|
||
class MassGrammarGenerator: | ||
def __init__(self): | ||
self.statusSummary = {-1:0, | ||
0:0, | ||
1:0, | ||
2:0} | ||
|
||
def __init__(self, n): | ||
self.statusSummary = {"LL1":0, "non-LL1":0} | ||
self.gc = GrammarChecker.GrammarChecker() | ||
self.g = SingleGrammarGenerator.SingleGrammarGenerator() | ||
|
||
#builds the ML model using our trainingData | ||
fI = os.path.join(script_dir, 'trainingData/'+str(n)+'var-interesting') | ||
fN = os.path.join(script_dir, 'trainingData/'+str(n)+'var-not-interesting') | ||
self.learnModel = SvmLearn.SvmLearn(n,fI,fN) | ||
|
||
def run(self,num, nonTerminals, terminals, writeToTxt = False): | ||
gc = GrammarChecker.GrammarChecker() | ||
g = SingleGrammarGenerator.SingleGrammarGenerator() | ||
n = len(nonTerminals) | ||
if writeToTxt: | ||
f = open(os.path.join(script_dir, 'data/'+str(n)+'Variables'), 'w') | ||
|
||
#generate num grammars and check them, discard the left hand recursion ones | ||
def run(self,num, nonTerminals, terminals): | ||
self.nonTerminals = nonTerminals | ||
self.terminals =terminals | ||
|
||
#generate num grammars, filter them and write the good ones to DB | ||
for i in range(0,num): | ||
grammar = g.generate(nonTerminals, terminals) | ||
firstSets, followSets, parsingTable, status, reachable = gc.solve(grammar,'A',False) | ||
self.statusSummary[status] += 1 | ||
if (not status == -1) and reachable: | ||
self.statusSummary[2] += 1 | ||
if writeToTxt: | ||
f.write(str(grammar)+'\n \tFirst Set: '+str(firstSets)+'\n \tFollow Set: '+str(followSets)+'\n \tReachable: '+ str(reachable) +'\n\n') | ||
else: | ||
#write to DB if not to TXT | ||
newG = Grammar(prods=str(grammar), nonTerminals=''.join(nonTerminals), terminals=''.join(terminals), startSymbol='A') | ||
newG.save() | ||
|
||
#LL1 Question | ||
ans = 'True' if status==0 else 'False' | ||
qLL = Question(gid=newG,qnum=0,category='LL',answer=ans) | ||
qLL.save() | ||
|
||
#ParseTable Question | ||
qPT = Question(gid=newG,qnum=1,category='PT',answer=str(parsingTable)) | ||
qPT.save() | ||
|
||
#First and Follow Set | ||
qnum = 2 | ||
for v in nonTerminals: | ||
qFirst = Question(gid=newG,qnum=qnum,category='FI',symbol=v,answer=''.join(firstSets[v])) | ||
qFirst.save() | ||
qnum +=1 | ||
qFollow = Question(gid=newG,qnum=qnum,category='FO',symbol=v,answer=''.join(followSets[v])) | ||
qFollow.save() | ||
qnum +=1 | ||
|
||
#print a small summary | ||
print(str(n)+"Variables:\nleft recursion: "+str(self.statusSummary[-1]) | ||
+"; LL(1): " + str(self.statusSummary[0]) | ||
+"; not LL(1): " + str(self.statusSummary[1]) | ||
+ "; Reachable: " + str(self.statusSummary[2])) | ||
self.createOneGrammar() | ||
|
||
#prints a small report | ||
print(str(len(self.nonTerminals)) + " Variables: " | ||
+ str(self.statusSummary["LL1"] + self.statusSummary["non-LL1"]) | ||
+ " interesting grammars picked out of "+str(num)+"\n\tLL1: " + str(self.statusSummary["LL1"]) | ||
+ "\n\tnot LL(1): " + str(self.statusSummary["non-LL1"])) | ||
|
||
def createOneGrammar(self): | ||
#This function randomly generates a single grammar, and saves it to the DB if | ||
#it is not left-recursion and interesting | ||
|
||
#generate a single grammar randomly | ||
grammar = self.g.generate(self.nonTerminals, self.terminals) | ||
|
||
#get answers using the checker | ||
#result = firstSets, followSets, parsingTable, status, reachable | ||
result = self.gc.solve(grammar,'A',False) | ||
|
||
#Abandon left recursive grammars and grammars with non-reachable variables | ||
if (result[3] == -1) or (not result[4]): | ||
return | ||
|
||
#If the ML model decidese it's interesting, save to DB | ||
prediction = self.learnModel.predictGrammar(grammar,result[0],result[1]) | ||
if prediction[0]==1: | ||
self.saveToDB(grammar,result) | ||
print("YES: "+str(grammar)+"\n\tFirst: "+str(result[0])+"\n\tFollow: "+str(result[1])) | ||
else: | ||
print("NO: "+str(grammar)+"\n\tFirst: "+str(result[0])+"\n\tFollow: "+str(result[1])) | ||
|
||
|
||
def saveToDB(self,grammar,result): | ||
#This function takes the grammar and the result returned by gc.solve. It | ||
#populates the Grammar and Question table in DB with the correct fields | ||
|
||
firstSets, followSets, parsingTable, status, reachable = result | ||
newG = Grammar(prods=str(grammar), nonTerminals=''.join(self.nonTerminals), | ||
terminals=''.join(self.terminals), startSymbol='A') | ||
newG.save() | ||
|
||
#First and Follow Set | ||
qnum = 0 | ||
for v in self.nonTerminals: | ||
qFirst = Question(gid=newG,qnum=qnum,category='FI', | ||
symbol=v,answer=''.join(firstSets[v])) | ||
qFirst.save() | ||
qnum +=1 | ||
|
||
for v in self.nonTerminals: | ||
qFollow = Question(gid=newG,qnum=qnum,category='FO', | ||
symbol=v,answer=''.join(followSets[v])) | ||
qFollow.save() | ||
qnum +=1 | ||
|
||
#LL1 Question | ||
if status == 0: | ||
ans = 'True' | ||
self.statusSummary["LL1"]+=1 | ||
else: | ||
ans = 'False' | ||
self.statusSummary["non-LL1"]+=1 | ||
qLL = Question(gid=newG,qnum=qnum,category='LL',answer=ans) | ||
qLL.save() | ||
qnum+=1 | ||
|
||
#Parse Table Question | ||
qPT = Question(gid=newG,qnum=qnum,category='PT',answer=str(parsingTable)) | ||
qPT.save() | ||
|
||
|
||
|
||
|
Oops, something went wrong.