'CHOPKINS 'Find all the possible scansions of Hopkins sprung-rhythm lines, given quantity, stress, and juncture, and ' sort them by a penalty score based on user-input constraint weights. 'Note to self: to add a constraint to this program: 'Put its name and weight in SetUpGrammar(), making sure you increment the number of constraints. 'Code it in ScansInitialOutride(), ScanW() or ScanS(), as appropriate. Option Explicit 'Module-level variables. Dim mNumberOfLines As Long 'The intact (not syllabified) text of a line: Dim mFullText() As String 'The syllable-by-syllable text: Dim mSyllables(1000, 30) As String 'Number of scansions of each line found by the program: Dim mNumberOfScansionsPerLine As Long 'Remember the input file header so it can be carried over to the output file: Dim mWholeFileHeader 'Basic structural variables. It is assumed there will never be more than 1000 lines or 30 syllables per line. Dim mStress(1000, 30) As Long Dim mJuncture(1000, 30) As Long Dim mWeight(1000, 30) As String 'What word the syllable belongs to. Dim mWordMembership(1000, 30) 'Annotation lines cover many things. They often begin with "feet n" to the number of feet in the line. Dim mAnnotation() As String 'Items reflecting Hopkins's own preferred scansions, as indicated by his diacritics. Dim mDiacritic(1000, 30) As Long 'Values: mS for Strong diacritics, mW for weak, mO for outride, zero for no diacritic. Const mS As Long = 1 Const mW As Long = 2 Const mO As Long = 3 Dim mRhyme(1000, 30) As Boolean 'Which syllables rhyme. Dim mCaesura(1000, 30) As Boolean 'Which syllables are preceded by a caesura mark. 'Number of feet (or, depending on your theory, strong positions) per line. Dim mDefaultNumberOfSPositions As Long 'Used to construct the column headers for the output file (W and S). Dim mNumberOfSPositions() As Long 'Whether a line is the first of its poem (and thus exempt from overreaving). ' The name is a bit misleading because this diacritit gets used in other contexts as well: ' stanza-initial in LE, or when Hopkins tells us in writing that overreaving is canceled. Dim mFirstLineOfPoem() As Boolean 'Structural variables that get calculated rather than read. 'Number of syllables in a line. Dim mNumberOfSyllables() As Long 'Number of lines in a pool, with different structural annotations of same text. Dim mPooled() As Long 'Variables for constraints: 'The set of violation counts is a local variable and thus not included here. Dim mNumberOfConstraints As Long Dim mConstraintNames(100) As String 'Taxonomy of constraints. 'Used only to find the Hopkins-preferred candidate. Dim mHopkinsDiacriticConstraint() As Boolean 'Inviolable; violators not printed out unless requested; not included in OTSoft file. Dim mInviolableConstraint() As Boolean 'Cancelled: used for programming different grammars (eliminated constraint from this grammar). Dim mCancelledConstraint() As Boolean 'The cost of violating each constraint. Mostly obsolete; we estimated these by hand before we reached ' the point of calculating them with maxent. In this program, they are hand-coded in SetUpGrammar(). Dim mCosts() As Single 'Status of an outride in various contexts. This is a bit silly but makes the program more mnemonic and modifiable. 'Currently assigned to outrides before 2 or 1 juncture. Const mBad As Long = 1 'Currently assigned to outrides before 3 juncture. Const mMarginal As Long = 3 'Currently assigned to outrides before 4 juncture. Const mNotQuiteRight As Long = 4 'Currently assigned to outrides before 5 juncture. Const mPerfect As Long = 5 'Variables for implementing overreaving. 'We need to know which previous line is best, and has the occupants of the final W position. ' This scansion will be used as the basis for checking potential overreaving problems in the following line. Dim mLowestCostPerLine As Single 'We give the number of overreavables (i.e. final W occupants) that the best preceding scansion has. 'Also, the phonological properties of the overreavables. 'First entry: previous line 'Second entry: current line Dim mOverreavablesInPreviousLine(2) As Long Dim mTextOfOverreavables(2, 5) As String Dim mStressOfOverreavables(2, 5) As Long Dim mJunctureOfOverreavables(2, 5) As Long Dim mWordOfOverreavables(2, 5) As String Dim mDiacriticOfOverreavables(2, 5) As Long Dim mWeightOfOverreavables(2, 5) As String 'Note: rhyme and caesura are not relevant -- they never matter in the first (overriven) W position. 'Keeping track of scansions -- so we don't duplicated scansions in the output file. 'A list of found scansions in text format. Dim mTotalScansions() As String Dim mTotalNumberOfScansions As Long 'Make a file for OTSoft/maxent purposes. 'I'm assuming no more than 2000 candidate scansions per line; this could cause crashes if the grammar ' changes, so watch for this. 'The following variables recode the basic variables of the program, given above. ' This is necessary because the input file has multiple codings of the same line, which must be collapsed ' in the maxent computations. Dim mOTSoftInputs(700) As String Dim mNumberOfOTSoftInputs As Long Dim mOTSoftCandidates(700, 2000) As String Dim mOTSoftWordAffiliations(700, 2000) As String Dim mNumberOfOTSoftCandidates(700) As Long Dim mOTSoftViolationVector(700, 2000) As String 'A Hopkins score indicates degree of deviation from what Hopkins annotated; it is used to establish ' the "winner" for training the constraint weights. ' Basis: 1 for contradicting a diacritic, 0.1 for outriding without Hopkins's testimony. Dim mOTSoftHopkinsScores(700, 2000) As Single 'Omit from the OTSoft file any candidates that will cause overreaving violations in conjunction with the following line. Dim mFinalPositionMustBeEmpty(700) As Boolean 'When there are more than one versions of the input, we need to collapse these together in the output file. This ' variable keeps track of the types that each input-token belongs to. Dim mAffiliatedTypizedLineIndex(700) As Long 'Files Dim mOutFile As Long 'Main report of what the program found. Dim mVerboseOutFile As Long 'Verbose output -- reports every step of scansion, for debugging purposes. Dim mVerboseOutputFlag As Boolean 'Indicates file above should be created. 'Trivia Dim TimeElapsed As Single '=================================================Interface Items===================================================== Private Sub Form_Load() 'This code gets executed when the program starts. On Error GoTo ErrorPoint Dim MyLine As String, MemFile As Long 'Center the form. Let Me.Left = (Screen.Width - Me.Width) / 2 Let Me.Top = (Screen.Height - Me.Height) / 2 'Find the last file read. Let MemFile = FreeFile Open App.Path + "/lastfileread.txt" For Input As #MemFile Line Input #MemFile, MyLine Close #MemFile Let txtFilename.Text = Trim(MyLine) 'Auto-fill specification of composite file for relevant file names. Select Case LCase(txtFilename.Text) Case "all.txt", "alloptimized.txt" Let chkAllAtOnce.Value = vbChecked End Select Exit Sub ErrorPoint: If Err.Number = 53 Then MsgBox "I can't find the file LastFileRead.txt. You'll have to enter by hand the file to be processed." Else MsgBox "Undiagnosed error on loading the form of this program: " + Err.Description End End If End Sub Private Sub cmdGo_Click() 'Launch the program. 'Reuse this button to exit once the program is done. Static ButtonStatus As Boolean If ButtonStatus = True Then Close End End If Let ButtonStatus = True 'Time the run. Let TimeElapsed = Timer 'The following gives the main organization of the program. Call RecordFileName Call ReadMainDataFile Call VetLinesForPhonologicalWellFormedness Call ReportLicenses Call EncodeHopkinsPreferences Call SetUpGrammar Call OpenOutputFiles Call PrintOutputFileHeaders Call LaunchScansion Call SortOutputFile Call PrintOTSoftFile Call AnnounceCompletion End Sub Sub RecordFileName() 'Remember what file you're working on, so you can launch quickly next time. Dim MyFile As Long Let MyFile = FreeFile Open App.Path + "/lastfileread.txt" For Output As #MyFile Print #MyFile, txtFilename.Text Close #MyFile End Sub Sub ReadMainDataFile() On Error GoTo ErrorPoint Dim MyLine As String Dim InFile As Long Dim LineIndex As Long, SyllableIndex As Long 'Open the input file. Let InFile = FreeFile Open App.Path + "/input/" + txtFilename.Text For Input As #InFile 'Get the default number of feet for this poem. Line Input #InFile, MyLine 'Save it for later. Let mWholeFileHeader = MyLine Let MyLine = s.TabTrim(MyLine) Let MyLine = s.Residue(MyLine) Let MyLine = s.Residue(MyLine) Let MyLine = s.Residue(MyLine) 'Deal with the slightly different format of an input file--multipoem or single poem. ' The standard file is multipoem. If chkAllAtOnce Then Let MyLine = s.Residue(MyLine) End If Let MyLine = s.TabTrim(MyLine) 'Check and warn for potential file format errors. If Not s.IsAnInteger(MyLine) Then MsgBox "Sorry, but I can't process this file due to formatting problems. " + _ "Please check the file against an old file known to have the correct format. " + _ "Note that single-poem and multi-poem files are formatted differently. " + _ "This program will exit when you click OK." End End If 'Grab the (default) number of feet per line. Let mDefaultNumberOfSPositions = Val(MyLine) 'Report progress. Let cmdGo.Caption = "Reading data file ..." 'Read and process each line of the input file. Do While Not EOF(InFile) 'Increment count and redimension arrays based on number of lines. Let mNumberOfLines = mNumberOfLines + 1 ReDim Preserve mFullText(mNumberOfLines) ReDim Preserve mNumberOfSPositions(mNumberOfLines) ReDim Preserve mNumberOfSyllables(mNumberOfLines) ReDim Preserve mAnnotation(mNumberOfLines) ReDim Preserve mFirstLineOfPoem(mNumberOfLines) ReDim Preserve mPooled(mNumberOfLines) 'Deal with the first line, which includes various information. See sample input file for what this is. Line Input #InFile, MyLine 'In a big file, ignore the grand line number. If chkAllAtOnce Then Let MyLine = s.Residue(MyLine) End If 'Ignore the line number and the line header. Let MyLine = s.Residue(s.Residue(MyLine)) 'In a big file, ignore the poem abbreviation. If chkAllAtOnce Then Let MyLine = s.Residue(MyLine) End If 'Record the full text (i.e. the legible version, no diacritics or annotation). Let mFullText(mNumberOfLines) = Trim(s.Chomp(MyLine)) Let MyLine = s.Residue(MyLine) 'In a big file, ignore the full text lacking the two-letter poem diacritic. If chkAllAtOnce Then Let MyLine = s.Residue(MyLine) End If 'Record the sequence of syllables Do If Trim(s.Chomp(MyLine)) = "" Then Exit Do 'Increment the number of syllables for this line. Let mNumberOfSyllables(mNumberOfLines) = mNumberOfSyllables(mNumberOfLines) + 1 'Grab the syllable itself. Let mSyllables(mNumberOfLines, mNumberOfSyllables(mNumberOfLines)) = s.Chomp(MyLine) Let MyLine = s.Residue(MyLine) Loop 'Record the sequence of stresses. Line Input #InFile, MyLine 'Ignore line-initial material, according to the input file type. If chkAllAtOnce Then Let MyLine = s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(MyLine)))))) Else Let MyLine = s.Residue(s.Residue(s.Residue(MyLine))) End If For SyllableIndex = 1 To mNumberOfSyllables(mNumberOfLines) 'Check the file to make sure it contains only legal stress values. Select Case s.Chomp(MyLine) Case "1", "2", "3", "4" Let mStress(mNumberOfLines, SyllableIndex) = Val(s.Chomp(MyLine)) Let MyLine = s.Residue(MyLine) Case Else MsgBox "Stress error in line #" + LTrim(Str(mNumberOfLines)) + mFullText(mNumberOfLines) + ". Illegal symbol is " + s.Chomp(MyLine) + ". Please fix before proceeding." End End Select Next SyllableIndex 'Watch for trailers. Let MyLine = s.Residue(MyLine) If Trim(s.Chomp(MyLine)) <> "" Then MsgBox "Error in line #" + LTrim(Str(mNumberOfLines)) + mFullText(mNumberOfLines) + ". Extra material after last stress. Please fix before proceeding." End End If 'Record the sequence of junctures. Line Input #InFile, MyLine 'Ignore line-initial material. If chkAllAtOnce Then Let MyLine = s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(MyLine)))))) Else Let MyLine = s.Residue(s.Residue(s.Residue(MyLine))) End If For SyllableIndex = 1 To mNumberOfSyllables(mNumberOfLines) 'Check the file to make sure it contains only legal juncture values. Select Case s.Chomp(MyLine) Case "1", "2", "3", "4", "5" 'It's ok, so recordit. Let mJuncture(mNumberOfLines, SyllableIndex) = s.Chomp(MyLine) Let MyLine = s.Residue(MyLine) Case Else MsgBox "Juncture error in line #" + LTrim(Str(mNumberOfLines)) + ". Illegal symbol is " + s.Chomp(MyLine) + ". Please fix before proceeding." End End Select Next SyllableIndex 'Watch for trailers. Let MyLine = s.Residue(MyLine) If Trim(s.Chomp(MyLine)) <> "" Then MsgBox "Error in line #" + LTrim(Str(mNumberOfLines)) + mFullText(mNumberOfLines) + ". Extra material after last juncture. Please fix before proceeding." End End If 'Record the sequence of weights. Line Input #InFile, MyLine 'Ignore line-initial material. If chkAllAtOnce Then Let MyLine = s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(MyLine)))))) Else Let MyLine = s.Residue(s.Residue(s.Residue(MyLine))) End If For SyllableIndex = 1 To mNumberOfSyllables(mNumberOfLines) 'Check the file to make sure it's ok. Select Case Trim(s.Chomp(MyLine)) 'The symbols used are - for heavy, v for light, and x for ambiguous weight. Case "-", "v", "x" 'Record the weight. Let mWeight(mNumberOfLines, SyllableIndex) = Trim(s.Chomp(MyLine)) Let MyLine = s.Residue(MyLine) Case Else MsgBox "Weight error in line #" + LTrim(Str(mNumberOfLines)) + ". Illegal symbol is " + s.Chomp(MyLine) + ". Please fix before proceeding." End End Select Next SyllableIndex 'Watch for trailers. Let MyLine = s.Residue(MyLine) If Trim(s.Chomp(MyLine)) <> "" Then MsgBox "Error in line #" + LTrim(Str(mNumberOfLines)) + mFullText(mNumberOfLines) + ". Extra material after last weight. Please fix before proceeding." End End If 'Record the sequence of word-memberships (what words the syllables belong to) Line Input #InFile, MyLine 'Ignore line-initial material. If chkAllAtOnce Then Let MyLine = s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(MyLine)))))) Else Let MyLine = s.Residue(s.Residue(s.Residue(MyLine))) End If For SyllableIndex = 1 To mNumberOfSyllables(mNumberOfLines) Let mWordMembership(mNumberOfLines, SyllableIndex) = Trim(s.Chomp(MyLine)) Let MyLine = s.Residue(MyLine) Next SyllableIndex 'Watch for trailers. Let MyLine = s.Residue(MyLine) If Trim(s.Chomp(MyLine)) <> "" Then MsgBox "Error in line #" + LTrim(Str(mNumberOfLines)) + mFullText(mNumberOfLines) + ". Extra material after last affiliated word. Please fix before proceeding." End End If 'Record the annotation. It contains various bits of information, separated by tabs, but it's ok to grab it ' as one single string. Line Input #InFile, MyLine 'Ignore line-initial material. If chkAllAtOnce Then Let MyLine = s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(s.Residue(MyLine)))))) Else Let MyLine = s.Residue(s.Residue(s.Residue(MyLine))) End If Let mAnnotation(mNumberOfLines) = s.TabTrim(MyLine) 'Extract relevant information from the annotation field. 'The number of S positions in the line: Let mNumberOfSPositions(mNumberOfLines) = NumberOfSPositions(mAnnotation(mNumberOfLines)) 'Whether this is the first line of a poem/stanza. This governs whether there ' will be overreaving, and also regulates what counts as the "preceding stress" ' or "preceding juncture" for constraint evaluation. Let mFirstLineOfPoem(mNumberOfLines) = FirstLineOfPoem(mAnnotation(mNumberOfLines)) 'Whether this is one of a set of different encodings of the same line ("pooled"). ' An integer, indicating position (1, 2, ...) in the pool. ' For non-pooled lines, it is set at zero. Let mPooled(mNumberOfLines) = Pooled(mAnnotation(mNumberOfLines)) Loop 'Go through all lines in the file. Close #1 'The first line of the file is assumed (for purposes of overreaving etc.) always to be the first line of a poem, ' no matter what the input file says. Let mFirstLineOfPoem(1) = True Exit Sub 'Debugging section: report what got stored in the arrays. Dim DebugFile As Long Let DebugFile = FreeFile Open "debug.txt" For Output As #DebugFile For LineIndex = 1 To mNumberOfLines For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) Print #DebugFile, mSyllables(LineIndex, SyllableIndex); Chr(9); Next SyllableIndex Print #DebugFile, For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) Print #DebugFile, mWeight(LineIndex, SyllableIndex); Chr(9); Next SyllableIndex Print #DebugFile, For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) Print #DebugFile, mStress(LineIndex, SyllableIndex); Chr(9); Next SyllableIndex Print #DebugFile, For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) Print #DebugFile, mJuncture(LineIndex, SyllableIndex); Chr(9); Next SyllableIndex Print #DebugFile, For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) Print #DebugFile, mWordMembership(LineIndex, SyllableIndex); Chr(9); Next SyllableIndex Print #DebugFile, Print #DebugFile, mAnnotation(LineIndex) Next LineIndex Close #DebugFile End ErrorPoint: If Err.Number = 53 Then 'File not found. MsgBox "I can't find the file " + txtFilename.Text + ". Please enter the name of some input file that is in the Input folder (daughter of the program folder)." ElseIf Err.Number = 62 Then 'Input past end of file: MsgBox "Problem. Probably, your input file has an extra blank line, possibly with tabs, at the end. So clean it up, ok, and then try again." End Else MsgBox "Undiagnosed error. The number of the error is " + Trim(Str(Err.Number)) + ". Contact xxx, sending him a copy of your input file." End If Unload Me End End Sub Function NumberOfSPositions(MyAnnotation As String) As Long 'This function reads off the line-specific number of feet from the input file. Let MyAnnotation = Trim(MyAnnotation) If LCase(Left(MyAnnotation, 4)) = "feet" Then 'Try to accommodate various formats. Let MyAnnotation = Mid(MyAnnotation, 5) If Left(MyAnnotation, 1) = ":" Or Left(MyAnnotation, 1) = Chr(9) Then Let MyAnnotation = Mid(MyAnnotation, 2) End If Let MyAnnotation = Trim(MyAnnotation) If s.IsAnInteger(Left(MyAnnotation, 1)) Then Let NumberOfSPositions = Val(Left(MyAnnotation, 1)) Else MsgBox "I'm having trouble reading the number of feet from the annotation line " + MyAnnotation + ". Please fix your input file and try again." End If Else Let NumberOfSPositions = mDefaultNumberOfSPositions End If End Function Function FirstLineOfPoem(MyAnnotation As String) As Boolean 'If the annotation line includes "poem initial" or some similar expression, record this as the first line of a poem. ' The purpose is to block overreaving. ' The code is verbose to help overcome possible variation in the file format. If Replace(LCase(MyAnnotation), "poem initial", "") <> LCase(MyAnnotation) Then Let FirstLineOfPoem = True ElseIf Replace(LCase(MyAnnotation), "poeminitial", "") <> LCase(MyAnnotation) Then Let FirstLineOfPoem = True ElseIf Replace(LCase(MyAnnotation), "poem-initial", "") <> LCase(MyAnnotation) Then Let FirstLineOfPoem = True ElseIf Replace(LCase(MyAnnotation), "stanza initial", "") <> LCase(MyAnnotation) Then Let FirstLineOfPoem = True ElseIf Replace(LCase(MyAnnotation), "stanzainitial", "") <> LCase(MyAnnotation) Then Let FirstLineOfPoem = True ElseIf Replace(LCase(MyAnnotation), "stanza-initial", "") <> LCase(MyAnnotation) Then Let FirstLineOfPoem = True Else Let FirstLineOfPoem = False End If End Function Function Pooled(MyAnnotation As String) As Long 'If the annotation line indicates that this coding is one of multiple codings of the same text, return its integer ' indicating position within the coding. ' The form of the code with "Replace" simply is a way to search for the string in question. If Replace(LCase(MyAnnotation), "pooled1", "") <> LCase(MyAnnotation) Then Let Pooled = 1 ElseIf Replace(LCase(MyAnnotation), "pooled2", "") <> LCase(MyAnnotation) Then Let Pooled = 2 ElseIf Replace(LCase(MyAnnotation), "pooled3", "") <> LCase(MyAnnotation) Then Let Pooled = 3 ElseIf Replace(LCase(MyAnnotation), "pooled4", "") <> LCase(MyAnnotation) Then Let Pooled = 4 Else Let Pooled = 0 End If End Function Function InversionAllowed(MyAnnotation As String) As Boolean 'This function returns True if the comment line includes the word "invertible". Dim Dummy As String Let Dummy = LCase(MyAnnotation) If Replace(Dummy, "invertible", "") <> Dummy Then Let InversionAllowed = True Else Let InversionAllowed = False End If End Function Sub EncodeHopkinsPreferences() 'Read through every syllable in the corpus and look for Hopkins diacritics, translating them into terms reflecting ' Hopkins's stated preferences (these are integer constants, defined at the top of the program): ' mS = must be scanned S ' mW = must be scanned W ' mO = must be scanned as an outride Dim MySyllable As String Dim LineIndex As Long, SyllableIndex As Long For LineIndex = 1 To mNumberOfLines For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) Let MySyllable = mSyllables(LineIndex, SyllableIndex) 'Do the mutually exclusive S/W/O diacritics. If s.Contains(MySyllable, "DBACCT") Then 'Double acute accent Let mDiacritic(LineIndex, SyllableIndex) = mS ElseIf s.Contains(MySyllable, "MACCT") Then 'Musical accent (> in "The Windhover") Let mDiacritic(LineIndex, SyllableIndex) = mS ElseIf s.Contains(MySyllable, "ACCT") Then 'Single acute accent. This is a substring of MACCT, but they yield 'the same outcome; so no worries. Let mDiacritic(LineIndex, SyllableIndex) = mS ElseIf s.Contains(MySyllable, "GCL") Then 'Diacritic placed on the syllables on either side of a great colon. Let mDiacritic(LineIndex, SyllableIndex) = mS ElseIf s.Contains(MySyllable, "DBGRV") Then 'Double grave accent Let mDiacritic(LineIndex, SyllableIndex) = mW ElseIf s.Contains(MySyllable, "OUTR") Then 'Outride Let mDiacritic(LineIndex, SyllableIndex) = mO End If 'Now add the diacritics that have more complex interpretations: rhyme (must be last S) and caesura (must be medial among S positions) If s.Contains(MySyllable, "RHM") Then 'Rhyme Let mRhyme(LineIndex, SyllableIndex) = True End If If s.Contains(MySyllable, "CSZ") Then 'Caesura Let mCaesura(LineIndex, SyllableIndex) = True End If Next SyllableIndex Next LineIndex End Sub Sub VetLinesForPhonologicalWellFormedness() 'Given the phonology of English and the coding system used, it is possible to some degree to ' pre-check the lines for phonological well-formedness. The output of this sub, a file ' called "VetLines.txt", must be checked by hand, since the coding is sometimes actually ' correct. Dim VetLines As Long Dim LineIndex As Long, SyllableIndex As Long Dim RhymeFound As Boolean 'Open the file that will store the results. Let VetLines = FreeFile Open App.Path + "/output/VetLines.txt" For Output As #VetLines 'Go through all the data. For LineIndex = 1 To mNumberOfLines 'You can't have consecutive stressed syllables within simplex word. For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) - 1 If mStress(LineIndex, SyllableIndex) > 1 Then If mJuncture(LineIndex, SyllableIndex) = 1 Then If mStress(LineIndex, SyllableIndex + 1) > 1 Then Print #VetLines, "1"; Chr(9); "In the line "; Chr(9); mFullText(LineIndex); Chr(9); Chr(9); "there are consecutive stresses in the same simplex word. This violates the transcription system used here and will produce very strange results under scansion." End If End If End If Next SyllableIndex 'Words cannot end in stressed light or ambiguous syllables. For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) If mStress(LineIndex, SyllableIndex) > 1 Then If mJuncture(LineIndex, SyllableIndex) > 1 Then If mWeight(LineIndex, SyllableIndex) <> "-" Then Print #VetLines, "2"; Chr(9); "In the line "; Chr(9); mFullText(LineIndex); Chr(9); "syllable"; Chr(9); ; mSyllables(LineIndex, SyllableIndex); Chr(9); ", there is a word-final stressed syllable, "", not marked heavy. This is impossible in English." End If End If End If Next SyllableIndex 'Phrases are generally not stressless. If mStress(LineIndex, 1) = 1 And mJuncture(LineIndex, SyllableIndex) >= 4 Then Print #VetLines, "3"; Chr(9); "In the line "; Chr(9); mFullText(LineIndex); Chr(9); "syllable"; Chr(9); ; mSyllables(LineIndex, 1); Chr(9); ", the first syllable may be stressless phrase all by itself -- check." End If For SyllableIndex = 2 To mNumberOfSyllables(LineIndex) If mStress(LineIndex, SyllableIndex) = 1 Then If mJuncture(LineIndex, SyllableIndex) >= 4 Then If mJuncture(LineIndex, SyllableIndex - 1) >= 4 Then Print #VetLines, "4"; Chr(9); "In the line "; Chr(9); mFullText(LineIndex); Chr(9); "syllable"; Chr(9); ; mSyllables(LineIndex, SyllableIndex); Chr(9); ", the syllable may be a stressless phrase all by itself -- check." End If End If End If Next SyllableIndex 'Alert the user if some line does not rhyme. We're done with this and it no longer needs to be activated. ' For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) ' If s.Contains(mSyllables(LineIndex, SyllableIndex), "RHM") Then GoTo ExitPoint ' Next SyllableIndex ' MsgBox "Caution: the line " + mFullText(LineIndex) + " is not marked for rhyme." ExitPoint: Next LineIndex Close #VetLines End Sub Sub OpenOutputFiles() 'Open files that will report the program output. On Error GoTo ErrorPoint 'Remember the filename of any output file being opened, for reporting errors to user. Dim FileBeingOpened As String 'Primary output file: Let FileBeingOpened = App.Path + "/output/Outputfor" + txtFilename.Text Let mOutFile = FreeFile Open FileBeingOpened For Output As #mOutFile 'Verbose output file, if asked. This shows every step of the (attempted) scansion. ' It is huge but can be very useful if used with short input files. If chkDiagnosisFile.Value = vbChecked Then Let FileBeingOpened = App.Path + "/output/VerboseOutputfor" + txtFilename.Text Let mVerboseOutFile = FreeFile Open FileBeingOpened For Output As #mVerboseOutFile Let mVerboseOutputFlag = True End If Exit Sub ErrorPoint: 'Let the user close an already-open output file without crashing. If Err.Number = 70 Then MsgBox "It appears that the file called " + FileBeingOpened + " is already open in some other program. Since I need to use this file, please close it in the other program, then click OK." Resume Else MsgBox "Fatal error. Please report this to xxx, specifying error #28945." End If End Sub Sub LaunchScansion() 'This goes through all the lines and launches the scansion process for each one. ' It also rescans the lines to check for violations that arise from overreaving. 'Variables: 'Basic variables for the system, passed recursively from routine to routine. ' The routines that participate in the passing process are this one, ScanW(), ScanS(), and ScanInitialOutride(). ' These arrays will represent complete lines at launch point, ' then are gradually shortened from left to right as recursive scansion takes place, digesting ' the syllables and positions. Dim LocalSyllable(30) As String 'syllable text Dim LocalWeight(30) As String Dim LocalStress(30) As Long Dim LocalJuncture(30) As Long Dim LocalWords(30) As String 'words affiliated with the syllables. Not used in the grammar, 'but rather for diagnosis of the theory (criteria of syllable weight). Dim LocalOverriven(30) As Boolean 'indicates which syllables have been carried over from the previous line ' as an overreaving test. 'Hopkins's diacritics: 'Diacritics marking S and W position. Reduced here to a simpler system. 'mS for strong-marking diacritics, mW for weak, mO for outride. Dim LocalDiacritic(30) As Long 'True if this syllable is marked as rhyming. Dim LocalRhyme(30) As Boolean 'True if this syllable is marked as coming just after the caesura mark, where present. Dim LocalCaesura(30) As Boolean 'For transmitting left-context information: Dim TransmittedPrecedingStress As Long Dim TransmittedPrecedingJuncture As Long Dim TransmittedPrecedingWeight As String 'These monitor whether a scansion is complete (this will be true when both are zero). Dim SyllablesLeft As Long Dim SPositionsLeft As Long 'The scansion found so far. Format: text of individual syllables, tab-delimited. Dim ScansionSoFar As String 'The words that go with the syllables of the scansion so far. Format: words, tab-delimited Dim WordAffiliationSoFar As String 'When there are more than one versions of the input, we need to collate these in the output file. This ' index is used for this function; it eventually gets stored in mAffiliatedTypizedLineIndex(), which ' has an entry for each line. Dim AffiliatedTypizedLineIndex As Long 'Transmit the number of constraint violations accumulated so far down the recursive chain. It will start out ' with zeros, since we are at the launch phase. Dim LocalViolationVector() As Long ReDim LocalViolationVector(mNumberOfConstraints) 'Flags Dim InversionOK As Boolean 'Tells you you are in the first W position, needed for "Brothers", which uniquely allows (initial) 'counterpointing: Dim LineInitial As Boolean 'Outrides are allowed only pentameter or longer. Must be evaluated on a line-by-line basis, for poems ' in which line length varies. Dim LineLongEnoughForOutride As Boolean 'Overreaving is impossible when we have the first line of a poem (multiple-poem input file), or when ' Hopkins says so in his commentaries. Dim NoOverreaving As Boolean 'When both overrove and normal scansions are calculated, user has options as to which ones to print out. Dim PrintMe As Boolean 'Variables used in accounting for overreaving. ' This is done by making a synthetic line, whose first syllables are the syllable in the final ' W position of the best scansion of the preceding line. 'When we incorporate the final-W syllables of the previous line, the syllable indexing will ' not be the same as in the original data file; hence renumbering is needed. Dim CurrentSyllable As Long 'Also, because the program sometimes gives both overrove and nonoverrove scansions, ' the number of lines that needed to be sorted and printed out is different from the number ' in the input file, so we need to renumber them, too. Dim PrintIndex As Long 'Simple indices for looping. Dim LineIndex As Long, SyllableIndex As Long, ConstraintIndex As Long 'Study each line of the poem. For LineIndex = 1 To mNumberOfLines 'Token-type issues. ' The input file often has multiple versions of the same line, coded differently. ' For maxent learning, we wish to pool these into single input. ' Thus, we must keep track of which tokens belong to which types. 'The AffiliatedTypizedLineIndex index, used below, goes up by one whenever there is a new type (as opposed to just ' a new token). This is deducible from the mPooled() variable, read off the input file. If mPooled(LineIndex) = 0 Or mPooled(LineIndex) = 1 Then Let AffiliatedTypizedLineIndex = AffiliatedTypizedLineIndex + 1 End If 'Remember what type this token belongs to. mAffiliatedTypizedLineIndex(LineIndex) = AffiliatedTypizedLineIndex 'If the user only wants overriven scansions (computed later) to be printed, remember this in a diacritic. If optOnlyOverreaving.Value = True Then Let PrintMe = False Else Let PrintMe = True 'We will be printing this one out, so give it a higher index for sorting. Let PrintIndex = PrintIndex + 1 End If 'Report progress to the user. Let cmdGo.Caption = "Now scanning line " + Trim(Str(LineIndex)) + "/" + Trim(Str(mNumberOfLines)) 'In the main output file, print a blank line, then a label for this line. If PrintMe Then 'Even blanks need to be numbered, since this file is going to be sorted later. ' We use a numbering system based on tens, with deviations based on details of the sort. ' This blank line gets sorted early. Print #mOutFile, Trim(Str(10 * PrintIndex - 3)) 'Now give a sorting index, the line number, and the legible text of the line. Print #mOutFile, Trim(Str(10 * PrintIndex - 2)); Chr(9); "Line "; Str(LineIndex); Chr(9); mFullText(LineIndex) End If 'Set variables in preparation for launching the scansion. 'Syllables left: all of them. Let SyllablesLeft = mNumberOfSyllables(LineIndex) 'S positions left: all of them. Let SPositionsLeft = mNumberOfSPositions(LineIndex) 'Nothing has been scanned yet: Let ScansionSoFar = "" Let WordAffiliationSoFar = "" 'Set up arrays for this line, in which each syllable is annotated for the phonological values. For SyllableIndex = 1 To SyllablesLeft Let LocalSyllable(SyllableIndex) = mSyllables(LineIndex, SyllableIndex) Let LocalWeight(SyllableIndex) = mWeight(LineIndex, SyllableIndex) Let LocalStress(SyllableIndex) = mStress(LineIndex, SyllableIndex) Let LocalJuncture(SyllableIndex) = mJuncture(LineIndex, SyllableIndex) Let LocalWords(SyllableIndex) = mWordMembership(LineIndex, SyllableIndex) Let LocalOverriven(SyllableIndex) = False Let LocalDiacritic(SyllableIndex) = mDiacritic(LineIndex, SyllableIndex) Let LocalRhyme(SyllableIndex) = mRhyme(LineIndex, SyllableIndex) Let LocalCaesura(SyllableIndex) = mCaesura(LineIndex, SyllableIndex) Next SyllableIndex 'Install information about the end of the preceding line, needed for scanning Hopkins. ' This is delicate, since sometime we encode more than one copy of a line. ' We only want to do it when we really are transitioning to a new line, not just a new copy. ' We can do this with the mPooled() variable, which is 0 or 1 for a new line. If mPooled(LineIndex) = 1 Or mPooled(LineIndex) = 0 Then 'Specify information about preceding line, if appropriate. If mFirstLineOfPoem(LineIndex) = True Then 'Transmitted Preceding juncture is 5 for the first line, else last juncture of last line. Let TransmittedPrecedingJuncture = 5 'You can never violate the MatchSW constraint on the very first line, so record an impossibly ' high value for the preceding "stress": Let TransmittedPrecedingStress = 10 'Weight is given a value that won't match any constraint. Let TransmittedPrecedingWeight = "" Else 'Copy these values from the preceding line. 'Fix me xxx hithere Let TransmittedPrecedingStress = mStress(LineIndex - 1, mNumberOfSyllables(LineIndex - 1)) Let TransmittedPrecedingJuncture = mJuncture(LineIndex - 1, mNumberOfSyllables(LineIndex - 1)) Let TransmittedPrecedingWeight = mWeight(LineIndex - 1, mNumberOfSyllables(LineIndex - 1)) End If 'Specify if poem initial Let NoOverreaving = mFirstLineOfPoem(LineIndex) 'Update the information about overreavable syllables in previous line, for purposes of overreaving. ' This moves the contents of Slot2 into Slot1, which will be filled in the current ' scansion. ' Slot 2 got filled in the course of scanning the preceding line; see below. Let mOverreavablesInPreviousLine(1) = mOverreavablesInPreviousLine(2) For SyllableIndex = 1 To 4 Let mTextOfOverreavables(1, SyllableIndex) = mTextOfOverreavables(2, SyllableIndex) Let mStressOfOverreavables(1, SyllableIndex) = mStressOfOverreavables(2, SyllableIndex) Let mJunctureOfOverreavables(1, SyllableIndex) = mJunctureOfOverreavables(2, SyllableIndex) Let mWordOfOverreavables(1, SyllableIndex) = mWordOfOverreavables(2, SyllableIndex) Let mDiacriticOfOverreavables(1, SyllableIndex) = mDiacriticOfOverreavables(2, SyllableIndex) Let mWeightOfOverreavables(1, SyllableIndex) = mWeightOfOverreavables(2, SyllableIndex) Next SyllableIndex 'Initialize costs. These values get picked as minima, so they must be initialized as high. ' When scansions are pooled, we should only initialize with a truly new line. Let mLowestCostPerLine = 1000000 Let mOverreavablesInPreviousLine(2) = 1000000 Let mNumberOfScansionsPerLine = 0 End If 'Is this the first line in a pool (same Hopkins text)? 'Set various boolean diacritics that govern scansion of particular line types. 'Establish if outrides are legal -- only in pentameter or longer. If mNumberOfSPositions(LineIndex) >= 5 Then Let LineLongEnoughForOutride = True Else Let LineLongEnoughForOutride = False End If 'Establish if inversion is ok, by reading the annotation. (Normally, inversion is *not* ok, ' and the coder must specify when it exceptionally is, as in "Brothers".) Let InversionOK = InversionAllowed(mAnnotation(LineIndex)) 'Establish that this is the beginning of a line. Let LineInitial = True 'Initialize the violation vector at no violations. For ConstraintIndex = 1 To mNumberOfConstraints Let LocalViolationVector(ConstraintIndex) = 0 Next ConstraintIndex 'Print the comment line, if nonnull, with a numbering that will cause it to be first. ' Do this only if the user has asked for this series (non-overrove) to be printed out. If PrintMe Then If Trim(mAnnotation(LineIndex)) <> "" Then Print #mOutFile, Trim(Str(10 * PrintIndex - 1)); Chr(9); Chr(9); mAnnotation(LineIndex) End If End If 'Initiate scansion. If NoOverreaving Then 'Don't bother with initial outrides in "separated line" contexts. 'Here, the first position you seek to fill is W. 'Start the scansion with a tab so it will line up with initial outride scansions. Let ScansionSoFar = Chr(9) Let WordAffiliationSoFar = Chr(9) Call ScanW(LineIndex, PrintIndex, SyllablesLeft, SPositionsLeft, ScansionSoFar, WordAffiliationSoFar, LocalSyllable(), _ LocalWeight(), TransmittedPrecedingWeight, _ LocalStress(), TransmittedPrecedingStress, _ LocalJuncture(), TransmittedPrecedingJuncture, _ LocalWords(), _ LocalOverriven(), _ LocalDiacritic(), LocalRhyme(), LocalCaesura(), _ LocalViolationVector(), _ InversionOK, LineInitial, LineLongEnoughForOutride, NoOverreaving, PrintMe) Else 'This line is preceded by close-knit line, and we're not at present looking for overreaving, ' so we can find the (Hopkins-attested) initial overreaving scansions. Call ScanInitialOutride(LineIndex, PrintIndex, SyllablesLeft, SPositionsLeft, ScansionSoFar, WordAffiliationSoFar, LocalSyllable(), _ LocalWeight(), TransmittedPrecedingWeight, _ LocalStress(), TransmittedPrecedingStress, _ LocalJuncture(), TransmittedPrecedingJuncture, _ LocalWords(), _ LocalOverriven(), _ LocalDiacritic(), LocalRhyme(), LocalCaesura(), _ LocalViolationVector(), _ InversionOK, LineInitial, LineLongEnoughForOutride, NoOverreaving, PrintMe) End If 'If you failed to find a scansion, and the user wants to know about this series (non-overrove), make a note. If PrintMe Then If mNumberOfScansionsPerLine = 0 Then Print #mOutFile, Trim(Str(10 * PrintIndex)); Chr(9); "0"; Chr(9); "XXX. Cannot scan this line." End If End If 'If the user so wishes, include the prosodic annotations. If PrintMe Then If chkPrintStructuralAnnotations.Value = vbChecked Then Call PrintProsodicAnnotations(LineIndex, PrintIndex, mNumberOfSyllables(LineIndex), LocalSyllable(), LocalStress(), LocalJuncture(), LocalWords(), LocalWeight()) End If End If 'Dealing with overreaving-------------------------------------------------------------------------------------------- 'Don't bother if the user rejected overreaving. If optNoOverreaving.Value = True Then GoTo SkipLineExitPoint End If 'No overreaving across consecutive poems in a file--you can't transmit overreavable syllables across the poem boundary. If mFirstLineOfPoem(LineIndex) = True Then Let mOverreavablesInPreviousLine(1) = 0 End If 'If the previous line could not be scanned, then the number of overreavables will have remained at its high ' default value. We need to start afresh, so reset to zero. If mOverreavablesInPreviousLine(1) = 1000000 Then Let mOverreavablesInPreviousLine(1) = 0 'If the user wants both overriven and non-overriven scansions, exit this routine if there is no need to execute ' it--you've already reported. ' the relevant outcome. If optMaxReportOverreaving = True Then If mOverreavablesInPreviousLine(1) = 0 Then GoTo SkipLineExitPoint End If End If 'Find the overrove scansions. 'This is going to be printed, if you've gotten this far. Let PrintMe = True 'Augment the PrintIndex, to provide a place in the output sort. Let PrintIndex = PrintIndex + 1 'Print a label for this set of scansions. Print #mOutFile, Trim(Str(10 * PrintIndex - 2)); Chr(9); Str(LineIndex); "O"; Chr(9); 'Specify that it was overriven only if it made a difference. If mOverreavablesInPreviousLine(1) > 0 Then Print #mOutFile, "with overreaving: "; End If Print #mOutFile, mFullText(LineIndex) 'Reinitialize. Let SyllablesLeft = mNumberOfSyllables(LineIndex) + mOverreavablesInPreviousLine(1) Let SPositionsLeft = mNumberOfSPositions(LineIndex) Let ScansionSoFar = "" Let WordAffiliationSoFar = "" Let mNumberOfScansionsPerLine = 0 'Form a synthetic line, which has been amplified by preposing the overreavable syllables ' of the preceding line. Let CurrentSyllable = 0 For SyllableIndex = 1 To mOverreavablesInPreviousLine(1) Let CurrentSyllable = CurrentSyllable + 1 Let LocalSyllable(CurrentSyllable) = mTextOfOverreavables(1, SyllableIndex) Let LocalStress(CurrentSyllable) = mStressOfOverreavables(1, SyllableIndex) Let LocalJuncture(CurrentSyllable) = mJunctureOfOverreavables(1, SyllableIndex) Let LocalWords(CurrentSyllable) = mWordOfOverreavables(1, SyllableIndex) Let LocalDiacritic(CurrentSyllable) = mDiacriticOfOverreavables(1, SyllableIndex) Let LocalWeight(CurrentSyllable) = mWeightOfOverreavables(1, SyllableIndex) 'Mark these as "phony syllables", to be printed solely as an overreaving test. Let LocalOverriven(CurrentSyllable) = True Next SyllableIndex For SyllableIndex = 1 To mNumberOfSyllables(LineIndex) Let CurrentSyllable = CurrentSyllable + 1 Let LocalSyllable(CurrentSyllable) = mSyllables(LineIndex, SyllableIndex) Let LocalWeight(CurrentSyllable) = mWeight(LineIndex, SyllableIndex) Let LocalStress(CurrentSyllable) = mStress(LineIndex, SyllableIndex) Let LocalJuncture(CurrentSyllable) = mJuncture(LineIndex, SyllableIndex) Let LocalWords(CurrentSyllable) = mWordMembership(LineIndex, SyllableIndex) Let LocalDiacritic(CurrentSyllable) = mDiacritic(LineIndex, SyllableIndex) Let LocalRhyme(CurrentSyllable) = mRhyme(LineIndex, SyllableIndex) Let LocalCaesura(CurrentSyllable) = mCaesura(LineIndex, SyllableIndex) Next SyllableIndex 'Initialize the violation vector at no violations. For ConstraintIndex = 1 To mNumberOfConstraints Let LocalViolationVector(ConstraintIndex) = 0 Next ConstraintIndex 'Scan: If mOverreavablesInPreviousLine(1) > 0 Then 'Here, it would make no sense to look for line-initial outrides, since the line now begins with ' material that really belongs to the last syllables. ' So start the scansion at W. 'Insert a tab in the output file so it will line up with initial outride scansions. Let ScansionSoFar = Chr(9) Let WordAffiliationSoFar = Chr(9) Call ScanW(LineIndex, PrintIndex, SyllablesLeft, SPositionsLeft, ScansionSoFar, WordAffiliationSoFar, LocalSyllable(), _ LocalWeight(), TransmittedPrecedingWeight, _ LocalStress(), TransmittedPrecedingStress, _ LocalJuncture(), TransmittedPrecedingJuncture, _ LocalWords(), _ LocalOverriven(), _ LocalDiacritic(), LocalRhyme(), LocalCaesura(), _ LocalViolationVector(), _ InversionOK, LineInitial, LineLongEnoughForOutride, NoOverreaving, PrintMe) Else 'Overreaving is not relevant here, but we still need to include all the scansions in the output file. Call ScanInitialOutride(LineIndex, PrintIndex, SyllablesLeft, SPositionsLeft, ScansionSoFar, WordAffiliationSoFar, LocalSyllable(), _ LocalWeight(), TransmittedPrecedingWeight, _ LocalStress(), TransmittedPrecedingStress, _ LocalJuncture(), TransmittedPrecedingJuncture, _ LocalWords(), _ LocalOverriven(), _ LocalDiacritic(), LocalRhyme(), LocalCaesura(), _ LocalViolationVector(), _ InversionOK, LineInitial, LineLongEnoughForOutride, NoOverreaving, PrintMe) End If ' N.B. do not call the routine for initial outrides, since this was already covered in the ' previous line. 'Start the scansion with a tab so it will line up with initial outride scansions. Let ScansionSoFar = Chr(9) Let WordAffiliationSoFar = Chr(9) 'Now you can scan: Call ScanW(LineIndex, PrintIndex, SyllablesLeft, SPositionsLeft, ScansionSoFar, WordAffiliationSoFar, LocalSyllable(), _ LocalWeight(), TransmittedPrecedingWeight, _ LocalStress(), TransmittedPrecedingStress, _ LocalJuncture(), TransmittedPrecedingJuncture, _ LocalWords(), _ LocalOverriven(), _ LocalDiacritic(), LocalRhyme(), LocalCaesura(), _ LocalViolationVector(), _ InversionOK, LineInitial, LineLongEnoughForOutride, NoOverreaving, PrintMe) 'If you failed to find an overriven scansion, look for a non-overriven scansion. If mNumberOfScansionsPerLine = 0 Then If optMaxReportOverreaving Then 'Give up now; you've already reported the nonoverriven scansion. Print #mOutFile, Trim(Str(10 * PrintIndex)); Chr(9); "0"; Chr(9); "Cannot scan this line with overreaving in effect." Else 'Trying to produce an economical report--only overriven scansions, notating when you have to cancel the overreaving. 'So, cancel the overreavables of the preceding line, and scan once. 'Set up arrays with just what gets passed on. Let SyllablesLeft = mNumberOfSyllables(LineIndex) Let SPositionsLeft = mNumberOfSPositions(LineIndex) Let ScansionSoFar = "" Let WordAffiliationSoFar = "" For SyllableIndex = 1 To SyllablesLeft Let LocalSyllable(SyllableIndex) = mSyllables(LineIndex, SyllableIndex) Let LocalWeight(SyllableIndex) = mWeight(LineIndex, SyllableIndex) Let LocalStress(SyllableIndex) = mStress(LineIndex, SyllableIndex) Let LocalJuncture(SyllableIndex) = mJuncture(LineIndex, SyllableIndex) Let LocalWords(SyllableIndex) = mWordMembership(LineIndex, SyllableIndex) Let LocalDiacritic(SyllableIndex) = mDiacritic(LineIndex, SyllableIndex) Let LocalRhyme(SyllableIndex) = mRhyme(LineIndex, SyllableIndex) Let LocalCaesura(SyllableIndex) = mCaesura(LineIndex, SyllableIndex) Let LocalOverriven(SyllableIndex) = False Next SyllableIndex 'Initialize the violation vector at no violations. For ConstraintIndex = 1 To mNumberOfConstraints Let LocalViolationVector(ConstraintIndex) = 0 Next ConstraintIndex 'Establish that this is the beginning of a line. Let LineInitial = True 'Initialize costs. These values get picked as minima, so they must be initialized as high. ' When scansions are pooled, we should only initialize with a truly new line. If mPooled(LineIndex) = 1 Or mPooled(LineIndex) = 0 Then Let mLowestCostPerLine = 1000000 Let mOverreavablesInPreviousLine(2) = 1000000 Let mNumberOfScansionsPerLine = 0 End If 'Scan. Initiate this process by calling the scansion routine for the first W position. If NoOverreaving Then 'Don't bother with initial outrides in "separated line" contexts. 'Start the scansion with a tab so it will line up with initial outride scansions. Let ScansionSoFar = Chr(9) Let WordAffiliationSoFar = Chr(9) 'Now scan: Call ScanW(LineIndex, PrintIndex, SyllablesLeft, SPositionsLeft, ScansionSoFar, WordAffiliationSoFar, LocalSyllable(), _ LocalWeight(), TransmittedPrecedingWeight, _ LocalStress(), TransmittedPrecedingStress, _ LocalJuncture(), TransmittedPrecedingJuncture, _ LocalWords(), _ LocalOverriven(), _ LocalDiacritic(), LocalRhyme(), LocalCaesura(), _ LocalViolationVector(), _ InversionOK, LineInitial, LineLongEnoughForOutride, NoOverreaving, PrintMe) Else 'This line is preceded by close-knit line, and we're not at present looking for overreaving, ' so we can find the (Hopkins-attested) initial overreaving scansions. Call ScanInitialOutride(LineIndex, PrintIndex, SyllablesLeft, SPositionsLeft, ScansionSoFar, WordAffiliationSoFar, LocalSyllable(), _ LocalWeight(), TransmittedPrecedingWeight, _ LocalStress(), TransmittedPrecedingStress, _ LocalJuncture(), TransmittedPrecedingJuncture, _ LocalWords(), _ LocalOverriven(), _ LocalDiacritic(), LocalRhyme(), LocalCaesura(), _ LocalViolationVector(), _ InversionOK, LineInitial, LineLongEnoughForOutride, NoOverreaving, PrintMe) End If 'Report what you found -- backup scansions, or failure. 'If PrintMe Then If mNumberOfScansionsPerLine = 0 Then Print #mOutFile, Trim(Str(10 * PrintIndex)); Chr(9); "0"; Chr(9); "XXX. Cannot scan this line, even when overreaving effects are ignored." Else Print #mOutFile, Trim(Str(10 * PrintIndex)); Chr(9); "0"; Chr(9); "XXX. Scannable, assuming the final W position of the preceding line is empty." 'If it's scannable only under these circumstances, we need to cancel some candidates of the prececing line. ' We can do this by referring to the types (not tokens; it's the shared input that matters). Let mFinalPositionMustBeEmpty(mAffiliatedTypizedLineIndex(LineIndex) - 1) = True 'Debug: Dim i As Long For i = 1 To 600 If mAffiliatedTypizedLineIndex(i) = mAffiliatedTypizedLineIndex(LineIndex) - 1 Then ' MsgBox "Tagged as requiring empty final W: " + mFullText(i) End If Next i End If 'End If End If 'Are you trying to produce an economical report? End If 'Did you fail to find an overriven scansion? 'If the user so wishes, include the prosodic annotations. If chkPrintStructuralAnnotations.Value = vbChecked Then Call PrintProsodicAnnotations(LineIndex, PrintIndex, SyllablesLeft, LocalSyllable(), LocalStress(), LocalJuncture(), LocalWords(), LocalWeight()) End If SkipLineExitPoint: Next LineIndex 'Loop through all the lines in the input file. 'Put a copy of the original header, with a zero. This permits the input file to be reconstructed ' from the output file, permitting diagnosis and editing all in one step. Call PrintSpacer(0, 0) Print #mOutFile, mWholeFileHeader 'Close the output file. Close #mOutFile 'Debug Dim DebugFile As Long Let DebugFile = FreeFile Open App.Path + "/debug.txt" For Output As DebugFile For i = 1 To mNumberOfLines Print #DebugFile, i; Chr(9); mAffiliatedTypizedLineIndex(i); Chr(9); mFullText(i); Chr(9); mFinalPositionMustBeEmpty(mAffiliatedTypizedLineIndex(i)) Next i Close #DebugFile End Sub Sub PrintOutputFileHeaders() 'Print a header Dim i As Long, SyllableIndex As Long 'The main output file 'Labels. Print #mOutFile, Chr(9); 'Print #mOutFile, " "; 'Initial outride: Print #mOutFile, Chr(9); "O"; 'W and S positions: For SyllableIndex = 1 To mDefaultNumberOfSPositions Print #mOutFile, Chr(9); "W"; Chr(9); "S"; Next SyllableIndex 'Always-present W: Print #mOutFile, Chr(9); "W"; 'Label (crucial to avoid sorting errors): Print #mOutFile, Chr(9); "Constraints:"; 'Column for sorting prosodic annotations: Print #mOutFile, Chr(9); "Sort input"; 'Constraint names: For i = 1 To mNumberOfConstraints Print #mOutFile, Chr(9); mConstraintNames(i); Next i Print #mOutFile, 'Another line with the weights: For i = 1 To 2 * mDefaultNumberOfSPositions + 2 Print #mOutFile, Chr(9); Next i Print #mOutFile, Chr(9); Chr(9); "Weights:"; Chr(9); For i = 1 To mNumberOfConstraints Print #mOutFile, Chr(9); mCosts(i); Next i Print #mOutFile, End Sub Sub ReportLicenses() 'Collate and report any licenses being used in scansion. Dim FileBeingOpened As String Dim MyLine As String, TargetString As String Dim LineIndex As Long, PositionIndex As Long, InnerPositionIndex As Long Dim LicensesFile As Long 'Open licences file Let LicensesFile = FreeFile Let FileBeingOpened = App.Path + "/output/LicencesFor" + txtFilename.Text Open FileBeingOpened For Output As #LicensesFile For LineIndex = 1 To mNumberOfLines Let MyLine = mAnnotation(LineIndex) If Replace(LCase(MyLine), "licence", "") <> LCase(MyLine) Or Replace(LCase(MyLine), "license", "") <> LCase(MyLine) Then 'Grab the particular part of the comment that you want. Let MyLine = Replace(MyLine, "icence", "icense") Let TargetString = "" For PositionIndex = 1 To Len(MyLine) - 7 + 1 Select Case Mid(LCase(MyLine), PositionIndex, 7) Case "licence", "license", "lisense", "lisence" For InnerPositionIndex = PositionIndex To Len(MyLine) If Mid(MyLine, InnerPositionIndex, 1) = Chr(9) Then Exit For Else Let TargetString = TargetString + Mid(MyLine, InnerPositionIndex, 1) End If Next InnerPositionIndex End Select Next PositionIndex 'Print what you found. Print #LicensesFile, mFullText(LineIndex); Chr(9); TargetString End If Next LineIndex End Sub Sub ScanW(LineIndex As Long, PrintIndex As Long, SyllablesLeft As Long, SPositionsLeft As Long, ScansionSoFar As String, WordAffiliationSoFar, LocalSyllable() As String, _ LocalWeight() As String, LocalPrecedingWeight As String, _ LocalStress() As Long, LocalPrecedingStress As Long, _ LocalJuncture() As Long, LocalPrecedingJuncture As Long, _ LocalWords() As String, _ LocalOverriven() As Boolean, _ LocalDiacritic() As Long, LocalRhyme() As Boolean, LocalCaesura() As Boolean, _ LocalViolationVector() As Long, _ InversionOK As Boolean, LineInitial As Boolean, LineLongEnoughForOutride As Boolean, NoOverreaving As Boolean, PrintMe As Boolean) 'Here begins the sequence of major routines that embody the metrical grammar. 'This routine inputs whatever is currently left of a line and meter, and parses all the legal sequences that can fill a W position. ' It will be called recursively, serving as part of a depth-first tree search. 'Variables to pass on values. These need to be separate, so they don't get changed by mistake. Dim TransmittedSyllablesLeft As Long Dim TransmittedSPositionsLeft As Long Dim TransmittedScansionSoFar As String Dim TransmittedWordAffiliationSoFar As String Dim TransmittedSyllable(30) As String Dim TransmittedStress(30) As Long Dim TransmittedJuncture(30) As Long Dim TransmittedWords(30) As String Dim TransmittedOverriven(30) As Boolean Dim TransmittedDiacritic(30) As Long Dim TransmittedRhyme(30) As Boolean Dim TransmittedCaesura(30) As Boolean Dim TransmittedWeight(30) As String Dim TransmittedPrecedingStress As Long Dim TransmittedPrecedingJuncture As Long Dim TransmittedPrecedingWeight As String 'Keeping track of the constraint violations run up so far. Dim TransmittedViolationVector() As Long ReDim TransmittedViolationVector(mNumberOfConstraints) Dim MyCost As Single Dim ShiftInterval As Long 'How many syllables consumed on this cycle. 'Indices Dim SyllableIndex As Long, NewSyllableIndex As Long, ConstraintIndex As Long, FootIndex As Long, DiacriticIndex As Long 'Record the violations obtained in scansion so far in the new variable. For ConstraintIndex = 1 To mNumberOfConstraints Let TransmittedViolationVector(ConstraintIndex) = LocalViolationVector(ConstraintIndex) Next ConstraintIndex 'We now do our tree search, going through all the possible daughters of a W node. 'Under very particular conditions, W can be a stressed non-final syllable of a word. ' These are that it be a poem that allows lexical inversion (according to Hopkins's own testimony), ' and that the W position be the first one in the line. If InversionOK Then 'Note: this flag is set as true only in initial position. If LocalJuncture(1) = 1 Then If LocalStress(1) > 1 Then 'We always indicate how many syllables of the line we have digested at a given stage; this is the ShiftInterval. Let ShiftInterval = 1 'Assess a penalty for stress in W position. ' The violation vector has a slot for each constraint, and to avoid error, this ' slot is looked up from the constraint name using the function n(). Let TransmittedViolationVector(n("StrInW")) = LocalViolationVector(n("StrInW")) + 1 'There are a number of violations that get assigned no matter what syllable has been digested. These are ' assessed with 60's era subroutines, which incur programmer disgrace but seem to work well here. ' In the present case we need to record incompatibility, if any, with Hopkins's diacritics. GoSub ScanW_DiacriticEvaluation 'Scan further. ScanW_InstallAndTransmit will carry out the recursive search. GoSub ScanW_InstallAndTransmit 'Now, you're back from searching that bit of the tree, and you're ready to take on a sister rather ' than a daughter node. To do this, you have to have the values in the variables that you started ' out with when you arrived at this node. GoSub ScanW_RestoreValues End If End If End If 'W can be any monosyllable, or any stressless syllable. Select Case LocalStress(1) Case 1 'Stressless syllable. This is cost-free unless there is a diacritic problem. Let ShiftInterval = 1 'Stressless Intonational Phrase-final *non*-outrides violate the constraint NoOutride5: If LocalJuncture(1) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If GoSub ScanW_AssessStressBasedViolations GoSub ScanW_DiacriticEvaluation GoSub ScanW_InstallAndTransmit GoSub ScanW_RestoreValues Case Else 'If a syllable is stressed, we can scan it only if it's a monosyllable (see disyllabic options below). ' We use the juncture and preceding juncture values to isolated a monosyllable. If LocalJuncture(1) > 1 And LocalPrecedingJuncture > 1 Then Let ShiftInterval = 1 GoSub ScanW_AssessStressBasedViolations GoSub ScanW_DiacriticEvaluation GoSub ScanW_InstallAndTransmit GoSub ScanW_RestoreValues End If End Select 'W can be a resolved disyllabic sequence: stressed light, followed by stressless light or ambiguous weight. 'Obviously,we can only do this if the line has at least two syllables left. If SyllablesLeft >= 2 Then If DisyllabicResolutionOk(LocalStress(1), LocalStress(2), LocalJuncture(1), LocalWeight(1), LocalWeight(2)) = True Then 'In words like "innocent", we don't want to scan /W inno /S cent /, ' since that violates the ban on lexical stress in W position. If SyllablesLeft >= 3 Then If LocalJuncture(2) = 1 And LocalStress(3) = 1 Then GoTo WExitPoint End If 'Likewise, in words like "dactylic", we don't want to scan /S dac /W tylic /, ' since that violates the ban on lexical stress in W position. If LocalPrecedingJuncture = 1 Then GoTo WExitPoint 'If you've passed these tests, you may now install the scansion with its affiliated violations. ' It uses up two syllables. Let ShiftInterval = 2 'Penalize for violating W Resolution: Let TransmittedViolationVector(n("WResol")) = LocalViolationVector(n("WResol")) + 1 'Stressless phrase-final non-outrides are penalized: If LocalJuncture(2) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If GoSub ScanW_AssessStressBasedViolations GoSub ScanW_DiacriticEvaluation GoSub ScanW_InstallAndTransmit GoSub ScanW_RestoreValues End If 'Are the basic conditions for disyllabic resolution met? End If 'Are there at least two syllables left? WExitPoint: 'Give up and go here if conditions are not met. 'In rare instances (and possibly not at all; it depends on your theory) W can be a trisyllabic sequence starting with a stressed light syllable. Let ShiftInterval = 3 If SyllablesLeft >= ShiftInterval Then If TrisyllabicResolutionOk(LocalStress(1), LocalStress(2), LocalStress(3), _ LocalJuncture(1), LocalJuncture(2), LocalJuncture(3), _ LocalWeight(1), LocalWeight(2), LocalWeight(3)) = True Then 'In words like "hesitancy", we don't want to scan /W hesitan /S cy /, ' since that violates the ban on lexical stress in W position. If SyllablesLeft >= 4 Then If LocalJuncture(2) = 1 And LocalJuncture(3) = 1 And LocalStress(4) = 1 Then GoTo WExitPoint2 End If 'Likewise, in words like "Eurydice", we don't want to scan /S Eu /W rydice /, ' since that violates the ban on lexical stress in W position. If LocalPrecedingJuncture = 1 Then GoTo WExitPoint2 'We will use DeLacean cumulativity, to always punish longer sequences more than shorter. 'Penalize for violating *Resolution 'Penalize for violating *Trisyllabic Resolution Let TransmittedViolationVector(n("WResol")) = LocalViolationVector(n("WResol")) + 1 Let TransmittedViolationVector(n("TriResol")) = LocalViolationVector(n("TriResol")) + 1 'Assess penalties based on stress: GoSub ScanW_AssessStressBasedViolations 'Stressless phrase-final non-outrides are penalized: If LocalJuncture(3) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If GoSub ScanW_AssessStressBasedViolations GoSub ScanW_DiacriticEvaluation GoSub ScanW_InstallAndTransmit GoSub ScanW_RestoreValues End If 'As the conditions on trisyllabic resolution met? End If 'Are there at least three syllables left? WExitPoint2: 'Give up and go here if conditions are not met. 'W can be a stressless disyllabic sequence if it contains no heavy syllables. If SyllablesLeft >= 2 Then If LocalWeight(1) = "v" Or LocalWeight(1) = "x" Then If LocalStress(1) = 1 Then If LocalWeight(2) = "x" Or LocalWeight(2) = "v" Then If LocalStress(2) = 1 Then 'Penalize for violating *2 Syllables in W Let TransmittedViolationVector(n("2SylInW")) = LocalViolationVector(n("2SylInW")) + 1 'Experiment: can a double outride ban improve getting the rhyme in dactylic-closing but finally-rhymed lines? ' Example: "But ah, but O thou terrible, why wouldst thou rude on me" ' This experiment failed, but we're keeping the code anyway since all constraints are user-cancellable. If SPositionsLeft = 0 Then Let TransmittedViolationVector(n("2SylInFinalW")) = LocalViolationVector(n("2SylInFinalW")) + 1 End If Let ShiftInterval = 2 'Stressless phrase-final non-outrides are penalized: If LocalJuncture(2) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If GoSub ScanW_AssessStressBasedViolations GoSub ScanW_DiacriticEvaluation GoSub ScanW_InstallAndTransmit GoSub ScanW_RestoreValues End If 'Is second syllable stressles? End If 'if second syllable light or medium? End If 'Is first syllable stressed? End If 'Is first syllable light? End If 'Are there at least two syllables left? 'W can be a stressless trisyllabic sequence of non-heavies. ' It's delicate what we mean by "stressless" here. "Hurrahing"'s "melted across skies" suggests allowing ' [2stress], but one worries what this will let in. ' We ended up deciding not to allow [2stress] in W and we ad hocly changed the input file to allow ' the "across" cases. The limits the practice to function words, which seems correct. Let ShiftInterval = 3 If SyllablesLeft >= ShiftInterval Then If LocalWeight(1) = "v" Or LocalWeight(1) = "x" Then If LocalStress(1) = 1 Then If LocalWeight(2) = "x" Or LocalWeight(2) = "v" Then If LocalStress(2) = 1 Then If LocalWeight(3) = "x" Or LocalWeight(3) = "v" Then If LocalStress(3) = 1 Then 'We will use DeLacean cumulativity, to always punish longer sequences more than shorter. 'Penalize for violating *3 Syllables in W 'Penalize for violating *2 Syllables in W Let TransmittedViolationVector(n("2SylInW")) = LocalViolationVector(n("2SylInW")) + 1 'And, if there are no more S positions left, penalize for violating *SylInFinalW. If SPositionsLeft = 0 Then Let TransmittedViolationVector(n("2SylInFinalW")) = LocalViolationVector(n("2SylInFinalW")) + 1 End If Let TransmittedViolationVector(n("3SylInW")) = LocalViolationVector(n("3SylInW")) + 1 'Stressless phrase-final non-outrides are penalized: If LocalJuncture(3) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If GoSub ScanW_AssessStressBasedViolations GoSub ScanW_DiacriticEvaluation GoSub ScanW_InstallAndTransmit GoSub ScanW_RestoreValues End If End If End If 'Is second syllable stressles? End If 'if second syllable light or medium? End If 'Is first syllable stressed? End If 'Is first syllable light? End If 'Are there at least two syllables left? 'W can be a stressless tetrasyllabic sequence of non-heavies. Let ShiftInterval = 4 If SyllablesLeft >= ShiftInterval Then If LocalWeight(1) = "v" Or LocalWeight(1) = "x" Then If LocalStress(1) = 1 Then If LocalWeight(2) = "x" Or LocalWeight(2) = "v" Then If LocalStress(2) = 1 Then If LocalWeight(3) = "x" Or LocalWeight(3) = "v" Then If LocalStress(3) = 1 Then If LocalWeight(4) = "x" Or LocalWeight(4) = "v" Then If LocalStress(4) = 1 Then 'We will use DeLacean cumulativity, to always punish longer sequences more than shorter. 'Penalize for violating *4 Syllables in W 'Penalize for violating *3 Syllables in W 'Penalize for violating *2 Syllables in W Let TransmittedViolationVector(n("2SylInW")) = LocalViolationVector(n("2SylInW")) + 1 'Special case for final W positions: If SPositionsLeft = 0 Then Let TransmittedViolationVector(n("2SylInFinalW")) = LocalViolationVector(n("2SylInFinalW")) + 1 End If Let TransmittedViolationVector(n("3SylInW")) = LocalViolationVector(n("3SylInW")) + 1 Let TransmittedViolationVector(n("4SylInW")) = LocalViolationVector(n("4SylInW")) + 1 'Stressless phrase-final non-outrides are penalized: If LocalJuncture(4) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If GoSub ScanW_AssessStressBasedViolations GoSub ScanW_DiacriticEvaluation GoSub ScanW_InstallAndTransmit GoSub ScanW_RestoreValues End If End If End If End If End If 'Is second syllable stressles? End If 'if second syllable light or medium? End If 'Is first syllable stressed? End If 'Is first syllable light? End If 'Are there at least two syllables left? 'W can be a stressless pentasyllabic sequence, at least in principle... Let ShiftInterval = 5 If SyllablesLeft >= ShiftInterval Then If LocalWeight(1) = "v" Or LocalWeight(1) = "x" Then If LocalStress(1) = 1 Then If LocalWeight(2) = "x" Or LocalWeight(2) = "v" Then If LocalStress(2) = 1 Then If LocalWeight(3) = "x" Or LocalWeight(3) = "v" Then If LocalStress(3) = 1 Then If LocalWeight(4) = "x" Or LocalWeight(4) = "v" Then If LocalStress(4) = 1 Then If LocalWeight(5) = "x" Or LocalWeight(5) = "v" Then If LocalStress(5) = 1 Then 'We will use DeLacean cumulativity, to always punish longer sequences more than shorter. 'Penalize for violating *5 Syllables in W 'Penalize for violating *4 Syllables in W 'Penalize for violating *3 Syllables in W 'Penalize for violating *2 Syllables in W Let TransmittedViolationVector(n("2SylInW")) = LocalViolationVector(n("2SylInW")) + 1 'Special case for final W positions: If SPositionsLeft = 0 Then Let TransmittedViolationVector(n("2SylInFinalW")) = LocalViolationVector(n("2SylInFinalW")) + 1 End If Let TransmittedViolationVector(n("3SylInW")) = LocalViolationVector(n("3SylInW")) + 1 Let TransmittedViolationVector(n("4SylInW")) = LocalViolationVector(n("4SylInW")) + 1 Let TransmittedViolationVector(n("5SylInW")) = LocalViolationVector(n("5SylInW")) + 1 'Stressless phrase-final non-outrides are penalized: If LocalJuncture(5) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If GoSub ScanW_AssessStressBasedViolations GoSub ScanW_DiacriticEvaluation GoSub ScanW_InstallAndTransmit GoSub ScanW_RestoreValues End If End If End If End If End If End If End If 'Is second syllable stressles? End If 'if second syllable light or medium? End If 'Is first syllable stressed? End If 'Is first syllable light? End If 'Are there at least two syllables left? 'W can be null. This involves the assessment of quite a few constraints. Let ShiftInterval = 0 'Violate constraint 1, "Empty W" 'Note: this will not record a violation for final empty W's, since the routine has already recorded a scansion. ' This seems correct to me. Let TransmittedViolationVector(n("EmptyW")) = TransmittedViolationVector(n("EmptyW")) + 1 ' According to the following constraint, an empty W is more disruptive to the meter when it is not the first of the line. If SPositionsLeft < mNumberOfSPositions(LineIndex) Then Let TransmittedViolationVector(n("MedialEmptyW")) = TransmittedViolationVector(n("MedialEmptyW")) + 1 End If 'It's worse to have an empty W when there is no stress clash flanking it. ' In initial position, this will depend on overreaving--a weak syllable at the end of the previous line ' will fill the W and void the violations. ' Thus, this arrangement will produce differences between overriven and nonoverriven scansions. ' We used the Boolean NoOverreaving diacritic to decide this. Select Case NoOverreaving Case False If LocalPrecedingStress = 1 Or LocalStress(1) = 1 Then Let TransmittedViolationVector(n("NoClashEmpW")) = TransmittedViolationVector(n("NoClashEmpW")) + 1 End If Case True If SPositionsLeft = mNumberOfSPositions(LineIndex) Then 'Initial W of a poem-initial line will violate if just the following syllable is stressless. If LocalStress(1) = 1 Then Let TransmittedViolationVector(n("NoClashEmpW")) = TransmittedViolationVector(n("NoClashEmpW")) + 1 End If Else 'Otherwise, just as before. If LocalPrecedingStress = 1 Or LocalStress(1) = 1 Then Let TransmittedViolationVector(n("NoClashEmpW")) = TransmittedViolationVector(n("NoClashEmpW")) + 1 End If End If End Select 'Constraints against empty positions after non-durationally-prominent syllables. If LineInitial = False Then 'They are very rare word-internally. We state this in stringency hierarchy terms. If LocalPrecedingJuncture = 1 Then Let TransmittedViolationVector(n("Post1EmpW")) = TransmittedViolationVector(n("Post1EmpW")) + 1 Let TransmittedViolationVector(n("Post2EmpW")) = TransmittedViolationVector(n("Post2EmpW")) + 1 End If 'They are rare Clitic-Group-internally: If LocalPrecedingJuncture = 2 Then Let TransmittedViolationVector(n("Post2EmpW")) = TransmittedViolationVector(n("Post2EmpW")) + 1 End If 'They are very rare after word-internal light syllables. 'Why word-internal? Well, "breaking lily / / locks" occurs, and seems not bad, but ' "li / / ly" would be terrible. ' Note: as it stands, this penalizes / disa- / / point / ment, which seems less bad; note also the ' claim of Kiparsky/Hopkins that resolved sequences count as syllables. Thus it might be better to limit the ' constraint to stressed syllables. It seems unlikely that even the modified constraint would ' reach statistical significance, however, so we have not bothered. If LocalPrecedingWeight = "v" And LocalPrecedingJuncture = 1 Then Let TransmittedViolationVector(n("PostLEmpW")) = TransmittedViolationVector(n("PostLEmpW")) + 1 End If End If 'Note: ScanW_DiacriticEvaluation is not called here, since under our notation system only syllables may bear diacritics. ' (Great colons are restated, à la Mackenzie, as equivalent acute accents.) 'You've now assessed all violations for empty W, so at this point you can keep scanning GoSub ScanW_InstallAndTransmit GoSub ScanW_RestoreValues 'Everything after this point is a GOSUB subroutine, so we must now exit sub. Exit Sub '---------------------------------------------------------------------------------------------------------------------------------------------------------------- ScanW_InstallAndTransmit: 'You've created and suitably penalized a scansion for this W position. Now record it and transmit ' it onward for scansion of the following S position. 'Keep track of what's left to do: Let TransmittedSyllablesLeft = SyllablesLeft - ShiftInterval Let TransmittedSPositionsLeft = SPositionsLeft 'Add the newly scanned syllables, and their affiliated words, to the scansion in progress. ' This takes the form of a string variable, containing the various scanned positions separated by tabs (Chr(9)). Let TransmittedScansionSoFar = ScansionSoFar + Chr(9) Let TransmittedWordAffiliationSoFar = WordAffiliationSoFar + Chr(9) For NewSyllableIndex = 1 To ShiftInterval Let TransmittedScansionSoFar = TransmittedScansionSoFar + " " + LocalSyllable(NewSyllableIndex) Let TransmittedWordAffiliationSoFar = TransmittedWordAffiliationSoFar + " " + LocalWords(NewSyllableIndex) Next NewSyllableIndex 'If user asked for it, report progress to the verbose output file: If mVerboseOutputFlag = True Then Let MyCost = ScansionCost(TransmittedViolationVector()) Print #mVerboseOutFile, MyCost; Chr(9); TransmittedScansionSoFar End If 'Check if you're done: 'Have you used all the syllables? If TransmittedSyllablesLeft = 0 Then 'Have you filled all the S positions? If TransmittedSPositionsLeft = 0 Then 'You've found a possible scansion. 'Assess its cost. 'Compute dot product. Let MyCost = ScansionCost(TransmittedViolationVector()) 'This will make a tedious output file if you include the really bad scansions. But do let the user overrride if they want. If MyCost < 1000 Or chkInviolable.Value = vbChecked Then Let mNumberOfScansionsPerLine = mNumberOfScansionsPerLine + 1 'Print it out if so desired. If PrintMe Then Call PrintOutAScansion(PrintIndex, MyCost, TransmittedScansionSoFar, TransmittedWordAffiliationSoFar, TransmittedViolationVector(), LineIndex, "W") End If 'For purposes of checking overreaving, keep track of whether this setting is best. 'Best means: lowest cost, and among these, fewest overreavable syllables. If MyCost < mLowestCostPerLine Or _ (MyCost = mLowestCostPerLine And ShiftInterval < mOverreavablesInPreviousLine(2)) Then Let mLowestCostPerLine = MyCost Let mOverreavablesInPreviousLine(2) = ShiftInterval 'Record the overreavables so they can be included in an overreaving test If ShiftInterval > 0 Then For SyllableIndex = 1 To ShiftInterval Let mTextOfOverreavables(2, SyllableIndex) = LocalSyllable(SyllableIndex) Let mStressOfOverreavables(2, SyllableIndex) = LocalStress(SyllableIndex) Let mJunctureOfOverreavables(2, SyllableIndex) = LocalJuncture(SyllableIndex) Let mWordOfOverreavables(2, SyllableIndex) = LocalWords(SyllableIndex) Let mDiacriticOfOverreavables(2, SyllableIndex) = LocalDiacritic(SyllableIndex) Let mWeightOfOverreavables(2, SyllableIndex) = LocalWeight(SyllableIndex) 'Note: mRhymeOfOverreavables() and mCaesuraOfOverreavables() are *not* coded, because they ' would never be relevant in the first W position of a line. Next SyllableIndex End If 'Are there any overreavables to record? End If 'Is this the best setting so far? 'You're done, so return to scansion. Return End If 'Is this line not so expensive that we want to skip it? Else 'You've used up the syllables, but not the S positions, so give up on this 'particular search path. Return End If ElseIf TransmittedSyllablesLeft > 0 And TransmittedSPositionsLeft > 0 And TransmittedSyllablesLeft >= TransmittedSPositionsLeft Then 'There are still some syllables to go, and there are enough to fill the remaining S positions, so keep scanning. 'Slide everything over: For SyllableIndex = 1 To SyllablesLeft - ShiftInterval Let TransmittedSyllable(SyllableIndex) = LocalSyllable(SyllableIndex + ShiftInterval) Let TransmittedWeight(SyllableIndex) = LocalWeight(SyllableIndex + ShiftInterval) Let TransmittedStress(SyllableIndex) = LocalStress(SyllableIndex + ShiftInterval) Let TransmittedJuncture(SyllableIndex) = LocalJuncture(SyllableIndex + ShiftInterval) Let TransmittedWords(SyllableIndex) = LocalWords(SyllableIndex + ShiftInterval) Let TransmittedOverriven(SyllableIndex) = LocalOverriven(SyllableIndex + ShiftInterval) Let TransmittedDiacritic(SyllableIndex) = LocalDiacritic(SyllableIndex + ShiftInterval) Let TransmittedRhyme(SyllableIndex) = LocalRhyme(SyllableIndex + ShiftInterval) Let TransmittedCaesura(SyllableIndex) = LocalCaesura(SyllableIndex + ShiftInterval) Next SyllableIndex 'What are the preceding stress and juncture for the next syllable? ' If you don't advance the window then, we assume that an empty position counts ' as zero, hence no spurious MatchWS violations. And the preceding juncture remains ' the same. If ShiftInterval = 0 Then Let TransmittedPrecedingStress = 0 Let TransmittedPrecedingJuncture = LocalPrecedingJuncture Let TransmittedPrecedingWeight = LocalPrecedingWeight Else Let TransmittedPrecedingStress = LocalStress(ShiftInterval) Let TransmittedPrecedingJuncture = LocalJuncture(ShiftInterval) Let TransmittedPrecedingWeight = LocalWeight(ShiftInterval) End If 'Call the scansion routine for the next position, which will be S. ' The arguments passed as False are: InversionOk and LineInitial, never relevant except ' line-initially. Call ScanS(LineIndex, PrintIndex, TransmittedSyllablesLeft, TransmittedSPositionsLeft, TransmittedScansionSoFar, TransmittedWordAffiliationSoFar, TransmittedSyllable(), _ TransmittedWeight(), TransmittedPrecedingWeight, _ TransmittedStress(), TransmittedPrecedingStress, _ TransmittedJuncture(), TransmittedPrecedingJuncture, _ TransmittedWords(), _ TransmittedOverriven(), _ TransmittedDiacritic(), TransmittedRhyme(), TransmittedCaesura(), _ TransmittedViolationVector(), False, False, LineLongEnoughForOutride, NoOverreaving, PrintMe) End If Return '---------------------------------------------------------------------------------------------------------------------------------------------------------------- ScanW_AssessStressBasedViolations: 'I. Violations that involve a stress in W. 'There are three ways that a stress can fill W: a monosyllable, a disyllabic resolution, or a trisyllabic resolution. ' In each case, we must regulate the W with respect to the preceding S. 'Penalize for violating Stress in W: If LocalStress(1) > 1 Then Let TransmittedViolationVector(n("StrInW")) = LocalViolationVector(n("StrInW")) + 1 End If 'Penalize for violating the Jespersenian ban of a "stress up" in a "meter down" location. If LocalStress(1) > LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchSW")) = LocalViolationVector(n("MatchSW")) + 1 'The classical Kiparskian phrase-final constraints (Kiparsky 1977, reinterpreted by Hayes 1983). ' At present, these are on hold, because when run with Maxent, they get zero weights. Maybe try again later. 'The constraint names are based on the examples Kiparsky uses: ' "Resembling strong youth in his middle age" ' "For good is the life, ending faithfully" 'So, checking the (additional) condition for these constraints: 'We need to be internal to some kind of phrase: If LocalPrecedingJuncture < LocalJuncture(1) Then 'P-phrase final. Note that we use a Delaceyan stringency hierarchy, both for stress and for juncture. If LocalJuncture(1) >= 4 Then Let TransmittedViolationVector(n("StrongYouth4")) = LocalViolationVector(n("StrongYouth4")) + 1 End If 'I-phrase final. If LocalJuncture(1) = 5 Then Let TransmittedViolationVector(n("StrongYouth5")) = LocalViolationVector(n("StrongYouth5")) + 1 End If 'The "the life" constraints are the same, but apply when the preceding syllable is stressless. If LocalPrecedingStress = 1 Then If LocalJuncture(1) >= 4 Then Let TransmittedViolationVector(n("TheLife4")) = LocalViolationVector(n("TheLife4")) + 1 End If If LocalJuncture(1) = 5 Then Let TransmittedViolationVector(n("TheLife5")) = LocalViolationVector(n("TheLife5")) + 1 End If End If 'Is the preceding syllable stressless? End If 'Is this a junctural domain? End If 'Is this a stress-rise where stress-fall is called for? 'In the final position of the line, the stress conditions are stricter; not only is it bad to rise into this position, but in addition ' (a) you can't even be level into this position; (b) the constraint appears to be inviolable. Hence the need to state it separately. If SPositionsLeft = 0 Then If LocalStress(1) >= LocalPrecedingStress Then Let TransmittedViolationVector(n("FinalFall")) = LocalViolationVector(n("FinalFall")) + 1 End If End If Return '---------------------------------------------------------------------------------------------------------------------------------------------------------------- ScanW_DiacriticEvaluation: 'Assess violations based on Hopkins's diacritics. This assumes the procedure-level index DiacriticIndex, designating a syllable. 'The ShiftInterval, always set prior to calling this subroutine, tells us how many syllables we must evaluate. 'Initialize: Let TransmittedViolationVector(n("HopIncompatS")) = LocalViolationVector(n("HopIncompatS")) Let TransmittedViolationVector(n("HopIncompatW")) = LocalViolationVector(n("HopIncompatW")) Let TransmittedViolationVector(n("HopRhyme")) = LocalViolationVector(n("HopRhyme")) Let TransmittedViolationVector(n("HopCaes")) = LocalViolationVector(n("HopCaes")) For DiacriticIndex = 1 To ShiftInterval 'Syllables diacritically marked as Strong or Outride can't go in W. Select Case LocalDiacritic(DiacriticIndex) Case mS TransmittedViolationVector(n("HopIncompatS")) = TransmittedViolationVector(n("HopIncompatS")) + 1 Case mO TransmittedViolationVector(n("HopIncompatO")) = TransmittedViolationVector(n("HopIncompatO")) + 1 End Select 'The strong syllable of a rhyme (which is marked in the corpus) can never go in Weak position. If LocalRhyme(DiacriticIndex) Then Let TransmittedViolationVector(n("HopRhyme")) = TransmittedViolationVector(n("HopRhyme")) + 1 End If 'If the caesura is marked, then preceding S's must equal following. If LocalCaesura(DiacriticIndex) Then If SPositionsLeft <> mNumberOfSPositions(LineIndex) / 2 Then Let TransmittedViolationVector(n("HopCaes")) = TransmittedViolationVector(n("HopCaes")) + 1 End If End If Next DiacriticIndex Return '---------------------------------------------------------------------------------------------------------------------------------------------------------------- ScanW_RestoreValues: 'Restore values. For ConstraintIndex = 1 To mNumberOfConstraints Let TransmittedViolationVector(ConstraintIndex) = LocalViolationVector(ConstraintIndex) Next ConstraintIndex Return End Sub Sub ScanS(LineIndex As Long, PrintIndex As Long, SyllablesLeft As Long, SPositionsLeft As Long, ScansionSoFar As String, WordAffiliationSoFar As String, _ LocalSyllable() As String, _ LocalWeight() As String, LocalPrecedingWeight As String, _ LocalStress() As Long, LocalPrecedingStress As Long, _ LocalJuncture() As Long, LocalPrecedingJuncture As Long, _ LocalWords() As String, _ LocalOverriven() As Boolean, _ LocalDiacritic() As Long, LocalRhyme() As Boolean, LocalCaesura() As Boolean, _ LocalViolationVector() As Long, _ InversionOK As Boolean, LineInitial As Boolean, LineLongEnoughForOutride As Boolean, NoOverreaving As Boolean, PrintMe As Boolean) 'This routine inputs whatever is currently left of a line and meter, and parses all the legal sequences that can ' fill an S position. 'Variables to pass on values, so that the ones in here don't get changed by mistake. Dim TransmittedSyllablesLeft As Long Dim TransmittedSPositionsLeft As Long Dim TransmittedScansionSoFar As String Dim TransmittedWordAffiliationSoFar As String Dim TransmittedSyllable(30) As String Dim TransmittedWeight(30) As String Dim TransmittedStress(30) As Long Dim TransmittedJuncture(30) As Long Dim TransmittedWords(30) As String Dim TransmittedOverriven(30) As Boolean Dim TransmittedDiacritic(30) As Long Dim TransmittedRhyme(30) As Boolean Dim TransmittedCaesura(30) As Boolean Dim TransmittedPrecedingStress As Long Dim TransmittedPrecedingJuncture As Long Dim TransmittedPrecedingWeight As String 'Information to work with here, and to pass on to the next iteration. Dim TransmittedViolationVector() As Long ReDim TransmittedViolationVector(mNumberOfConstraints) Dim ShiftInterval As Long 'How many syllables consumed on this cycle. Dim OutrideCount As Long 'Did the current proposed scansion use an outride? 'Dim DappleFlag As Boolean 'Are we scanning with a resolved S? Dim MyCost As Single 'The cost of a scansion Dim SyllableWindow As Long 'How many syllables for assessing Hopkins's diacritics Dim FirstOutride As Long 'How many syllables for assessing Hopkins's diacritics -- outrides Dim LastOutride As Long 'How many syllables for assessing Hopkins's diacritics -- outrides 'Indices Dim SyllableIndex As Long, NewSyllableIndex As Long, ConstraintIndex As Long, FootIndex As Long, OutrideIndex As Long, DiacriticIndex As Long 'We assume that overriven syllables from the preceding line are never placed in S. So we can truncate the search very ' fast in such cases. If LocalOverriven(1) Then 'MsgBox "Get out of ScanS due to overreaving. Line is: " + mFullText(LineIndex) Exit Sub End If 'Localize the transmitted information For ConstraintIndex = 1 To mNumberOfConstraints Let TransmittedViolationVector(ConstraintIndex) = LocalViolationVector(ConstraintIndex) Next ConstraintIndex '1 syllable: S can be either stressed or heavy (Kiparsky, p. 319) ' But if it is light, or stressless, there is a complexity penalty. If SyllablesLeft >= 1 Then If LocalStress(1) > 1 Or LocalWeight(1) <> "v" Then Let ShiftInterval = 1 'Penalize stressless syllables in S (adumbrated in Kiparsky, p. 318) If LocalStress(1) = 1 Then Let TransmittedViolationVector(n("StrlsInS")) = LocalViolationVector(n("StrlsInS")) + 1 'Stressless phrase-final non-outrides are penalized: If LocalJuncture(1) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If End If 'Penalize light syllables in S (adumbrated in Kiparsky, p. 318) If LocalWeight(1) = "v" Then Let TransmittedViolationVector(n("LightInS")) = LocalViolationVector(n("LightInS")) + 1 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Hopkins's diacritics Let SyllableWindow = 1 GoSub ScanS_DiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Is this stressed or heavy? End If '2 syllables: disyllabic Resolution If SyllablesLeft >= 2 Then If DisyllabicResolutionOk(LocalStress(1), LocalStress(2), LocalJuncture(1), LocalWeight(1), LocalWeight(2)) = True Then Let ShiftInterval = 2 'Incur a violation of SResol, the ban on Strong Resolution. Let TransmittedViolationVector(n("SResol")) = LocalViolationVector(n("SResol")) + 1 'To count the preceding stress right, we need to remember we are using a resolved scansion. On hold for now. 'Let DappleFlag = True 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Stressless phrase-final non-outrides are penalized: If LocalJuncture(2) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If 'Hopkins's diacritics Let SyllableWindow = 2 GoSub ScanS_DiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are the conditions for disyllabic resolution met? End If 'Are there at least two syllables left? '2 syllables: stressed syllable followed by a single outride. If SyllablesLeft >= 2 Then If SingleOutrideOk(LocalStress(1), LocalJuncture(1), LocalStress(2), LocalJuncture(2)) Then Let ShiftInterval = 2 'Penalize light syllables in S. If LocalWeight(1) = "v" Then Let TransmittedViolationVector(n("LightInS")) = LocalViolationVector(n("LightInS")) + 1 'Assess a penalty for *Outride. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 'Assess a penalty for *Outride3 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(2)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 'DeLaceyan stringency hierarchy: Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Cause a > to appear in the scansion, denoting an outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 1 'Hopkins's diacritics: Let SyllableWindow = 1 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 2 Let LastOutride = 2 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are the conditions for a single outride met? End If 'Are there at least two syllables left? '3 syllables: Resolution. If SyllablesLeft >= 3 Then If TrisyllabicResolutionOk(LocalStress(1), LocalStress(2), LocalStress(3), _ LocalJuncture(1), LocalJuncture(2), LocalJuncture(3), _ LocalWeight(1), LocalWeight(2), LocalWeight(3)) = True Then Let ShiftInterval = 3 'Incur a violation of TriResol, the ban on triple resolutions. Let TransmittedViolationVector(n("TriResol")) = LocalViolationVector(n("TriResol")) + 1 'Following DeLacyan principles, also incur a violation of SResol, the ban on Strong Resolution. Let TransmittedViolationVector(n("SResol")) = LocalViolationVector(n("SResol")) + 1 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Stressless phrase-final non-outrides are penalized: If LocalJuncture(3) = 5 Then Let TransmittedViolationVector(n("NoOutride5")) = TransmittedViolationVector(n("NoOutride5")) + 1 End If 'Hopkins's diacritics: Let SyllableWindow = 3 GoSub ScanS_DiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are the conditions for trisyllabic resolution met? End If 'Are there at least three syllables left? '3 syllables: Disyllabic Resolution plus a single outride syllable. If SyllablesLeft >= 3 Then If DisyllabicResolutionOk(LocalStress(1), LocalStress(2), LocalJuncture(1), LocalWeight(1), LocalWeight(2)) Then 'Note parameters called: it's LocalJuncture(2) that has to be considered, forcing it to be weaker than LocalJuncture(3). If SingleOutrideOk(LocalStress(1), LocalJuncture(2), LocalStress(3), LocalJuncture(3)) Then Let ShiftInterval = 3 'This is both a resolution and an outride, so assess penalties for *SResol and *Outride. Let TransmittedViolationVector(n("SResol")) = LocalViolationVector(n("SResol")) + 1 Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(3)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Cause a > to appear in the scansion, denoting an outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 1 'Hopkins's diacritics: Let SyllableWindow = 2 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 3 Let LastOutride = 3 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are conditions on outrides met? End If 'Are conditions on Resolution met? End If 'Are there at least three syllables left? '3 syllables: 1 in S, double outride. If SyllablesLeft >= 3 Then If DoubleOutrideOk(LocalStress(1), LocalJuncture(1), LocalStress(2), LocalJuncture(2), LocalWeight(2), LocalStress(3), LocalJuncture(3), LocalWeight(3)) Then Let ShiftInterval = 3 'Assess penalties for *Outride and *DoubleOutR. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("DoubleOutR")) = LocalViolationVector(n("DoubleOutR")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(3)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess violations of *LightInS. If LocalWeight(1) = "v" Then Let TransmittedViolationVector(n("LightInS")) = LocalViolationVector(n("LightInS")) + 1 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Cause >> to appear in the scansion, denoting a double outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 2 'Hopkins's diacritics: Let SyllableWindow = 1 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 2 Let LastOutride = 3 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'double outride ok? End If 'Are there at least three syllables left? '3 syllables: 1 in S, resolved outride. If SyllablesLeft >= 3 Then If ResolvedOutrideOk(LocalStress(1), LocalJuncture(1), LocalStress(2), LocalJuncture(2), LocalWeight(2), LocalStress(3), LocalJuncture(3), LocalWeight(3)) Then Let ShiftInterval = 3 'Assess violations of *LightInS (unlikely here). If LocalWeight(1) = "v" Then Let TransmittedViolationVector(n("LightInS")) = LocalViolationVector(n("LightInS")) + 1 'Assess penalties for *Outride and *Resolved Outride. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("ResolOutR")) = LocalViolationVector(n("ResolOutR")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(3)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Cause >> to appear in the scansion, denoting two outrides. (Hopkins's mark is translated as "O"). Let OutrideCount = 2 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Hopkins's diacritics: Let SyllableWindow = 1 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 2 Let LastOutride = 3 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Is the relative-stress requirement on outrides met? End If 'Are there at least three syllables left? '4 syllables: 1 in S, triple outride. 'For this to arise, 1 must be stressed, and (redundantly) it must bear more stress than 2 and 3 and 4. '2 and 3 cannot be heavy, and must be stressless. If SyllablesLeft >= 4 Then If TripleOutrideOk(LocalStress(1), LocalJuncture(1), _ LocalStress(2), LocalJuncture(2), LocalWeight(2), _ LocalStress(3), LocalJuncture(3), LocalWeight(3), _ LocalStress(4), LocalJuncture(4), LocalWeight(4)) Then Let ShiftInterval = 4 'Assess penalties for *Outride, *DoubleOutR, and *TripleOutR, following the principles of the stringency hierarchy. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("DoubleOutR")) = LocalViolationVector(n("DoubleOutR")) + 1 Let TransmittedViolationVector(n("TripleOutR")) = LocalViolationVector(n("TripleOutR")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(4)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess violations of *LightInS. If LocalWeight(1) = "v" Then Let TransmittedViolationVector(n("LightInS")) = LocalViolationVector(n("LightInS")) + 1 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Cause >>> to appear in the scansion, denoting a triple outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 3 'Hopkins's diacritics: Let SyllableWindow = 1 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 2 Let LastOutride = 4 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are the requirements for triple outride met? End If 'Are there at least four syllables left? '4 syllables: 1 in S and a trisyllabic resolved outride. If SyllablesLeft >= 4 Then If ResolvedTripleOutrideOk(LocalStress(1), LocalJuncture(1), _ LocalStress(2), LocalJuncture(2), LocalWeight(2), _ LocalStress(3), LocalJuncture(3), LocalWeight(3), _ LocalStress(4), LocalJuncture(4), LocalWeight(4)) Then Let ShiftInterval = 4 'Assess violations of *LightInS (unlikely here) If LocalWeight(1) = "v" Then Let TransmittedViolationVector(n("LightInS")) = LocalViolationVector(n("LightInS")) + 1 'Assess penalties for *Outride, *Resolved Outride, and *Trisyllabic Resolution. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("ResolOutR")) = LocalViolationVector(n("ResolOutR")) + 1 Let TransmittedViolationVector(n("TriResol")) = LocalViolationVector(n("TriResol")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(4)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Cause >>> to appear in the scansion, denoting an outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 3 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Hopkins's diacritics: Let SyllableWindow = 1 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 2 Let LastOutride = 4 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are the requirements for a trisyllabic resolved outride met? End If 'Are there at least four syllables left? '4 syllables: resolution and a double outride. ' We've only seen this in one place, i.e. in "Heraclitean Fire", with the diacritically-enforced "Foot-fretted in it". But it is implied by the ' cases already given, and ought to be included. If SyllablesLeft >= 4 Then If DisyllabicResolutionOk(LocalStress(1), LocalStress(2), LocalJuncture(1), LocalWeight(1), LocalWeight(2)) = True Then If DoubleOutrideOk(LocalStress(1), LocalJuncture(2), LocalStress(3), LocalJuncture(3), LocalWeight(3), LocalStress(4), LocalJuncture(4), LocalWeight(4)) Then Let ShiftInterval = 4 'This is both a resolution and an outride, so assess penalties for *SResol and *Outride. Let TransmittedViolationVector(n("SResol")) = LocalViolationVector(n("SResol")) + 1 Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("DoubleOutR")) = LocalViolationVector(n("DoubleOutR")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(4)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Cause a > to appear in the scansion, denoting a double outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 2 'Hopkins's diacritics: Let SyllableWindow = 2 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 3 Let LastOutride = 4 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are the requirements for a double outride met? End If 'Are the requirements for disyllabic resolution met? End If 'Are there at least four syllables left? '4 syllables: resolution and a resolved outride. ' A hypothetical possibility, but implied by all the others. If SyllablesLeft >= 4 Then If DisyllabicResolutionOk(LocalStress(1), LocalStress(2), LocalJuncture(1), LocalWeight(1), LocalWeight(2)) = True Then If ResolvedOutrideOk(LocalStress(1), LocalJuncture(2), LocalStress(3), LocalJuncture(3), LocalWeight(3), LocalStress(4), LocalJuncture(4), LocalWeight(4)) Then Let ShiftInterval = 4 'This is two resolutions and an outride. Assess penalties. Let TransmittedViolationVector(n("SResol")) = LocalViolationVector(n("SResol")) + 1 Let TransmittedViolationVector(n("ResolOutR")) = LocalViolationVector(n("ResolOutR")) + 1 Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(4)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Cause >> to appear in the scansion, denoting a double outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 2 'Hopkins's diacritics: Let SyllableWindow = 2 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 3 Let LastOutride = 4 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are the requirements for a double outride met? End If 'Are the requirements for disyllabic resolution met? End If 'Are there at least four syllables left? '4 syllables: Trisyllabic Resolution plus a single outride syllable. If SyllablesLeft >= 4 Then If TrisyllabicResolutionOk(LocalStress(1), LocalStress(2), LocalStress(3), LocalJuncture(1), LocalJuncture(2), LocalJuncture(3), _ LocalWeight(1), LocalWeight(2), LocalWeight(3)) Then 'Note parameters called: it's LocalJuncture(3) that has to be considered, forcing it to be weaker than LocalJuncture(3). If SingleOutrideOk(LocalStress(1), LocalJuncture(3), LocalStress(4), LocalJuncture(4)) Then Let ShiftInterval = 4 'This is both a resolution and an outride, so assess penalties. Let TransmittedViolationVector(n("SResol")) = LocalViolationVector(n("SResol")) + 1 Let TransmittedViolationVector(n("TriResol")) = LocalViolationVector(n("TriResol")) + 1 Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(4)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Cause a > to appear in the scansion, denoting an outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 1 'Hopkins's diacritics: Let SyllableWindow = 3 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 4 Let LastOutride = 4 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are conditions on outrides met? End If 'Are conditions on Resolution met? End If 'Are there at least four syllables left? '5 syllables: resolution and a triple outride. If SyllablesLeft >= 5 Then If DisyllabicResolutionOk(LocalStress(1), LocalStress(2), LocalJuncture(1), LocalWeight(1), LocalWeight(2)) = True Then If TripleOutrideOk(LocalStress(1), LocalJuncture(2), _ LocalStress(3), LocalJuncture(3), LocalWeight(3), _ LocalStress(4), LocalJuncture(4), LocalWeight(4), _ LocalStress(5), LocalJuncture(5), LocalWeight(5)) Then Let ShiftInterval = 5 'This is both a resolution and an outride, so assess appropriate penalties. Let TransmittedViolationVector(n("SResol")) = LocalViolationVector(n("SResol")) + 1 Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("DoubleOutR")) = LocalViolationVector(n("DoubleOutR")) + 1 Let TransmittedViolationVector(n("TripleOutR")) = LocalViolationVector(n("TripleOutR")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(5)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess violations of *MatchWS. If LocalStress(1) < LocalPrecedingStress Then Let TransmittedViolationVector(n("MatchWS")) = LocalViolationVector(n("MatchWS")) + 1 'Assess penalties for outrides in short lines. GoSub ScanS_PenalizeOutridesInShortLines 'Cause a > to appear in the scansion, denoting a double outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 3 'Hopkins's diacritics: Let SyllableWindow = 2 GoSub ScanS_DiacriticEvaluation Let FirstOutride = 3 Let LastOutride = 5 GoSub ScanS_OutrideDiacriticEvaluation GoSub ScanS_InstallAndTransmit GoSub ScanS_RestoreValues End If 'Are the requirements for a triple outride met? End If 'Are the requirements for disyllabic resolution met? End If 'Are there at least five syllables left? 'We could go on to include the remaining possibilities for 5 syllable S positions (2 resolved + 3 resolved, 3 resolved + 2, 3 resolved + 2 resolved) ' and the two possibilities for 6 syllables (3 resolved + 3, 3 resolved + 3 resolved) but this seems to involve diminishing returns; the relevant ' linguistic configurations are quite rare. For instance, the option above adds only four candidates, all involving "Poetry to it" in "Ashboughs." Exit Sub '------------------------------------------------------------------------------------------------------------------------------------------------------ ScanS_PenalizeOutridesInShortLines: 'Assess penalties for outrides in short lines. 'July 2009: simplify to just one constraint. If LineLongEnoughForOutride = False Then 'If SyllablesLeft = ShiftInterval Then 'Final, probably pretty harmless: 'Let TransmittedViolationVector(n("FinOutRShortLine")) = LocalViolationVector(n("FinOutRShortLine")) + 1 'Else 'Non-final, pernicious: Let TransmittedViolationVector(n("OutRShortLine")) = LocalViolationVector(n("OutRShortLine")) + 1 'End If End If Return '------------------------------------------------------------------------------------------------------------------------------------------------------ ScanS_DiacriticEvaluation: 'Record incompatibility with Hopkins's diacritics. 'Initialize, to permit cumulation of violations. This also covers the outride subroutine, below. Let TransmittedViolationVector(n("HopIncompatS")) = LocalViolationVector(n("HopIncompatS")) Let TransmittedViolationVector(n("HopIncompatW")) = LocalViolationVector(n("HopIncompatW")) Let TransmittedViolationVector(n("HopIncompatO")) = LocalViolationVector(n("HopIncompatO")) Let TransmittedViolationVector(n("HopNoSupport")) = LocalViolationVector(n("HopNoSupport")) 'We loop through the syllables until we get to SyllableWindow, the total under consideration. For DiacriticIndex = 1 To SyllableWindow 'Assess a violation if this S-position scansion contradicts a diacritic that specifies Weak or Outride position. If DiacriticIndex = 1 Then Select Case LocalDiacritic(DiacriticIndex) Case mW Let TransmittedViolationVector(n("HopIncompatW")) = TransmittedViolationVector(n("HopIncompatW")) + 1 Case mO Let TransmittedViolationVector(n("HopIncompatO")) = TransmittedViolationVector(n("HopIncompatO")) + 1 End Select Else 'Second and third position cannot be marked for anything--must have the default marking. 'I.e., we assume that if Hopkins put in two accents, he would have meant two strong positions. Select Case LocalDiacritic(DiacriticIndex) Case mS TransmittedViolationVector(n("HopIncompatS")) = TransmittedViolationVector(n("HopIncompatS")) + 1 Case mW TransmittedViolationVector(n("HopIncompatW")) = TransmittedViolationVector(n("HopIncompatW")) + 1 Case mO TransmittedViolationVector(n("HopIncompatO")) = TransmittedViolationVector(n("HopIncompatO")) + 1 End Select End If 'Diacritic for rhyme. Only the last S position can rhyme. Only the first syllable of an S position can rhyme. If LocalRhyme(DiacriticIndex) Then If SPositionsLeft > 1 Or DiacriticIndex > 1 Then Let TransmittedViolationVector(n("HopRhyme")) = LocalViolationVector(n("HopRhyme")) + 1 End If End If 'Diacritic for caesura. It must divide the line evenly. If LocalCaesura(DiacriticIndex) Then If SPositionsLeft <> mNumberOfSPositions(LineIndex) / 2 Then Let TransmittedViolationVector(n("HopCaes")) = LocalViolationVector(n("HopCaes")) + 1 End If End If Next DiacriticIndex Return '------------------------------------------------------------------------------------------------------------------------------------------------------ ScanS_OutrideDiacriticEvaluation: For DiacriticIndex = FirstOutride To LastOutride 'Record incompatibility if you have made into an outride a syllables marked for S or W. Select Case LocalDiacritic(DiacriticIndex) Case mW, mS TransmittedViolationVector(n("HopIncompatO")) = TransmittedViolationVector(n("HopIncompatO")) + 1 End Select 'Record lack of support if you have made into an outride a syllable not diacritically marked for this purpose. If LocalDiacritic(DiacriticIndex) <> mO Then TransmittedViolationVector(n("HopNoSupport")) = TransmittedViolationVector(n("HopNoSupport")) + 1 End If 'Outrides cannot rhyme. Note that the rhyme diacritic will only occur once per line, so no need to accumulate violations. If LocalRhyme(DiacriticIndex) Then Let TransmittedViolationVector(n("HopRhyme")) = LocalViolationVector(n("HopRhyme")) + 1 End If 'Diacritic for caesura. It must divide the line evenly. Note that the caesura diacritic will only occur once per line, so no need to accumulate violations. If LocalCaesura(DiacriticIndex) Then If SPositionsLeft <> mNumberOfSPositions(LineIndex) / 2 Then Let TransmittedViolationVector(n("HopCaes")) = LocalViolationVector(n("HopCaes")) + 1 End If End If Next DiacriticIndex Return '------------------------------------------------------------------------------------------------------------------------------------------------------ ScanS_InstallAndTransmit: 'You've created and suitably penalized a scansion for this position. Now record it and transmit ' it onward for scansion of the next position. 'Keep track of what's left to do: Let TransmittedSyllablesLeft = SyllablesLeft - ShiftInterval Let TransmittedSPositionsLeft = SPositionsLeft - 1 'Debug: isn't this program wasting effort? ' If TransmittedSPositionsLeft = -1 Then Stop 'Add the newly scanned syllables to the scansion in progress: Let TransmittedScansionSoFar = ScansionSoFar + Chr(9) Let TransmittedWordAffiliationSoFar = WordAffiliationSoFar + Chr(9) For NewSyllableIndex = 1 To ShiftInterval Let TransmittedScansionSoFar = TransmittedScansionSoFar + " " + LocalSyllable(NewSyllableIndex) Let TransmittedWordAffiliationSoFar = TransmittedWordAffiliationSoFar + " " + LocalWords(NewSyllableIndex) Next NewSyllableIndex ' Stop 'Add diacritics to show how many outride syllables are present: For OutrideIndex = 1 To OutrideCount Let TransmittedScansionSoFar = TransmittedScansionSoFar + ">" Next OutrideIndex 'If user asked for it, report progress to the verbose output file: If mVerboseOutputFlag = True Then Let MyCost = ScansionCost(TransmittedViolationVector()) Print #mVerboseOutFile, MyCost; Chr(9); TransmittedScansionSoFar End If 'Check if you're done: If TransmittedSyllablesLeft = 0 Then 'Have you filled all the S positions? If TransmittedSPositionsLeft = 0 Then 'You've found a possible scansion. 'This will make a tedious output file, and mess up the maxent modeling, if you include the really bad scansions. 'Compute dot product. Let MyCost = ScansionCost(TransmittedViolationVector()) If MyCost < 1000 Or chkInviolable.Value = vbChecked Then Let mNumberOfScansionsPerLine = mNumberOfScansionsPerLine + 1 'For purposes of checking overreaving, keep track of whether this setting is best. 'Best means, lowest cost, and among these, fewest overreavable syllables. 'MsgBox "Cost: " + Str(MyCost) + ". scansion is: " + TransmittedScansionSoFar If MyCost < mLowestCostPerLine Or _ (MyCost = mLowestCostPerLine And ShiftInterval < mOverreavablesInPreviousLine(2)) Then Let mLowestCostPerLine = MyCost Let mOverreavablesInPreviousLine(2) = 0 'There is no need to record the properties of the overreavables since there aren't any. End If 'Is this the best setting so far? 'Print it out if so desired. If PrintMe Then Call PrintOutAScansion(PrintIndex, MyCost, TransmittedScansionSoFar, TransmittedWordAffiliationSoFar, TransmittedViolationVector(), LineIndex, "S") End If End If 'Is this a scansion worth recording? Else 'Otherwise, it's a failed scansion and can be ignored. End If Return ElseIf TransmittedSyllablesLeft >= TransmittedSPositionsLeft Then 'Provided you have enough syllables to fill the remaining S positions, keep scanning. 'Slide everything over: For SyllableIndex = 1 To SyllablesLeft - ShiftInterval Let TransmittedSyllable(SyllableIndex) = LocalSyllable(SyllableIndex + ShiftInterval) Let TransmittedWeight(SyllableIndex) = LocalWeight(SyllableIndex + ShiftInterval) Let TransmittedStress(SyllableIndex) = LocalStress(SyllableIndex + ShiftInterval) Let TransmittedJuncture(SyllableIndex) = LocalJuncture(SyllableIndex + ShiftInterval) Let TransmittedWords(SyllableIndex) = LocalWords(SyllableIndex + ShiftInterval) Let TransmittedOverriven(SyllableIndex) = LocalOverriven(SyllableIndex + ShiftInterval) Let TransmittedDiacritic(SyllableIndex) = LocalDiacritic(SyllableIndex + ShiftInterval) Let TransmittedRhyme(SyllableIndex) = LocalRhyme(SyllableIndex + ShiftInterval) Let TransmittedCaesura(SyllableIndex) = LocalCaesura(SyllableIndex + ShiftInterval) Next SyllableIndex 'What is the preceding stress for the next syllable? We'll assume that an empty position counts ' as zero, hence no spurious MatchWS violations. If ShiftInterval = 0 Then Let TransmittedPrecedingStress = 0 Let TransmittedPrecedingJuncture = LocalPrecedingJuncture Let TransmittedPrecedingWeight = LocalPrecedingWeight Else 'When S is filled with a dapple word, the "preceding stress" is counted as the ' stress on dap-, not on -ple. 'xxx Hmm., this is now pretty controversial! The original purpose of this gambit was to get scansions like ' apple / 0 / pie. But if stressed lights can fill S, as we now believe, then ' this would probably be scanned ap / ple / pie. 'So I've commented out the controversial stuff for now. 'Not so fast! 'For lines like prose-sample ' the lowest in the commonwealth. 'It seems plausible to treat "wealth" as being in W position--but right now, this isn't happening, because "mon" is taken as the ' preceding syllable. 'Ponder, inspecting the real data. 'If DappleFlag = True Then ' Let TransmittedPrecedingStress = LocalStress(ShiftInterval - 1) 'Else Let TransmittedPrecedingStress = LocalStress(ShiftInterval) 'End If Let TransmittedPrecedingJuncture = LocalJuncture(ShiftInterval) Let TransmittedPrecedingWeight = LocalWeight(ShiftInterval) End If 'Call the scansion routine: ' The last two arguments are, InversionOk and LineInitial, never relevant except line-initially. Call ScanW(LineIndex, PrintIndex, _ TransmittedSyllablesLeft, TransmittedSPositionsLeft, TransmittedScansionSoFar, TransmittedWordAffiliationSoFar, TransmittedSyllable(), _ TransmittedWeight(), TransmittedPrecedingWeight, _ TransmittedStress(), TransmittedPrecedingStress, _ TransmittedJuncture(), TransmittedPrecedingJuncture, _ TransmittedWords(), _ TransmittedOverriven(), _ TransmittedDiacritic(), TransmittedRhyme(), TransmittedCaesura(), _ TransmittedViolationVector(), _ False, False, LineLongEnoughForOutride, NoOverreaving, PrintMe) End If Return '---------------------------------------------------------------------------------------------------------------------------------------------------------------- ScanS_RestoreValues: 'Restore values. For ConstraintIndex = 1 To mNumberOfConstraints Let TransmittedViolationVector(ConstraintIndex) = LocalViolationVector(ConstraintIndex) Next ConstraintIndex Let OutrideCount = 0 Return End Sub Sub ScanInitialOutride(LineIndex As Long, PrintIndex As Long, _ SyllablesLeft As Long, SPositionsLeft As Long, ScansionSoFar As String, WordAffiliationSoFar As String, _ LocalSyllable() As String, _ LocalWeight() As String, LocalPrecedingWeight As String, _ LocalStress() As Long, LocalPrecedingStress As Long, _ LocalJuncture() As Long, LocalPrecedingJuncture As Long, _ LocalWords() As String, _ LocalOverriven() As Boolean, _ LocalDiacritic() As Long, LocalRhyme() As Boolean, LocalCaesura() As Boolean, _ LocalViolationVector() As Long, _ InversionOK As Boolean, LineInitial As Boolean, LineLongEnoughForOutride As Boolean, NoOverreaving As Boolean, PrintMe As Boolean) 'Hopkins occasionally begins a line with an outride, so we need to include this as a possibility. ' This routine gets called in these circumstances: we're outride-eligible, but not scanning for ' overreaving (because there are no posttonic syllables at the end of the preceding line). 'Variables to pass on values, so that the ones in here don't get changed by mistake. Dim TransmittedSyllablesLeft As Long Dim TransmittedSPositionsLeft As Long Dim TransmittedScansionSoFar As String Dim TransmittedWordAffiliationSoFar As String Dim TransmittedSyllable(30) As String Dim TransmittedWeight(30) As String Dim TransmittedStress(30) As Long Dim TransmittedJuncture(30) As Long Dim TransmittedWords(30) As String Dim TransmittedOverriven(30) As Boolean Dim TransmittedDiacritic(30) As Long Dim TransmittedRhyme(30) As Boolean Dim TransmittedCaesura(30) As Boolean Dim TransmittedPrecedingStress As Long Dim TransmittedPrecedingJuncture As Long Dim TransmittedPrecedingWeight As String Dim TransmittedInversionOk As Boolean 'Information to work with here, and to pass on to the next iteration. Dim TransmittedViolationVector() As Long ReDim TransmittedViolationVector(mNumberOfConstraints) Dim ShiftInterval As Long 'How many syllables consumed on this cycle. Dim OutrideCount As Long 'Did the current proposed scansion use an outride? Dim MyCost As Single 'The cost of a scansion Dim FirstOutride As Long 'How many syllables for assessing Hopkins's diacritics -- outrides Dim LastOutride As Long 'How many syllables for assessing Hopkins's diacritics -- outrides 'Indices Dim SyllableIndex As Long, NewSyllableIndex As Long, ConstraintIndex As Long, FootIndex As Long, OutrideIndex As Long, DiacriticIndex As Long '1 syllable: you must be weaker stress than the last syllable of the preceding line, and your ' juncture must be stronger than the juncture that ended the preceding line. If SyllablesLeft >= 1 Then If SingleOutrideOk(LocalPrecedingStress, LocalPrecedingJuncture, LocalStress(1), LocalJuncture(1)) Then Let ShiftInterval = 1 'Assess a penalty for *Outride. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(1)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess penalty for line-initial outride Let TransmittedViolationVector(n("LineInitOutR")) = LocalViolationVector(n("LineInitOutR")) + 1 'Assess penalties for outrides in short lines. GoSub ScanIO_PenalizeOutridesInShortLines 'Cause a > to appear in the scansion, denoting an outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 1 'Hopkins's diacritics: Let FirstOutride = 1 Let LastOutride = 1 GoSub ScanIO_OutrideDiacriticEvaluation GoSub ScanIO_InstallAndTransmit GoSub ScanIO_RestoreValues End If 'Are the conditions for a single outride met? End If 'Are there at least one syllable left? '2 syllables: double outride. If SyllablesLeft >= 2 Then If DoubleOutrideOk(LocalPrecedingStress, LocalPrecedingJuncture, LocalStress(1), LocalJuncture(1), LocalWeight(1), LocalStress(2), LocalJuncture(2), LocalWeight(2)) Then Let ShiftInterval = 2 'Assess penalties for *Outride and *DoubleOutR. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("DoubleOutR")) = LocalViolationVector(n("DoubleOutR")) + 1 'Assess penalty for line-initial outride Let TransmittedViolationVector(n("LineInitOutR")) = LocalViolationVector(n("LineInitOutR")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(2)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess penalties for outrides in short lines. GoSub ScanIO_PenalizeOutridesInShortLines 'Cause >> to appear in the scansion, denoting a double outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 2 'Hopkins's diacritics: Let FirstOutride = 1 Let LastOutride = 2 GoSub ScanIO_OutrideDiacriticEvaluation GoSub ScanIO_InstallAndTransmit GoSub ScanIO_RestoreValues End If 'double outride ok? End If 'Are there at least two syllables left? '2 syllables: resolved outride. If SyllablesLeft >= 2 Then If ResolvedOutrideOk(LocalPrecedingStress, LocalPrecedingJuncture, LocalStress(1), LocalJuncture(1), LocalWeight(1), LocalStress(2), LocalJuncture(2), LocalWeight(2)) Then Let ShiftInterval = 2 'Assess penalties for *Outride and *Resolved Outride. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("ResolOutR")) = LocalViolationVector(n("ResolOutR")) + 1 'Assess penalty for line-initial outride Let TransmittedViolationVector(n("LineInitOutR")) = LocalViolationVector(n("LineInitOutR")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(2)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess penalties for outrides in short lines. GoSub ScanIO_PenalizeOutridesInShortLines 'Cause >> to appear in the scansion, denoting two outrides. (Hopkins's mark is translated as "O"). Let OutrideCount = 2 'Hopkins's diacritics: Let FirstOutride = 1 Let LastOutride = 2 GoSub ScanIO_OutrideDiacriticEvaluation GoSub ScanIO_InstallAndTransmit GoSub ScanIO_RestoreValues End If 'Are requirements for resolved outrides met? End If 'Are there at least two syllables left? '3 syllables: triple outride. If SyllablesLeft >= 3 Then If TripleOutrideOk(LocalPrecedingStress, LocalPrecedingJuncture, _ LocalStress(1), LocalJuncture(1), LocalWeight(1), _ LocalStress(2), LocalJuncture(2), LocalWeight(2), _ LocalStress(3), LocalJuncture(3), LocalWeight(3)) Then Let ShiftInterval = 3 'Assess penalties for *Outride, *DoubleOutR, and *TripleOutR, following the principles of the stringency hierarchy. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("DoubleOutR")) = LocalViolationVector(n("DoubleOutR")) + 1 Let TransmittedViolationVector(n("TripleOutR")) = LocalViolationVector(n("TripleOutR")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(3)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess penalty for line-initial outride Let TransmittedViolationVector(n("LineInitOutR")) = LocalViolationVector(n("LineInitOutR")) + 1 'Assess penalties for outrides in short lines. GoSub ScanIO_PenalizeOutridesInShortLines 'Cause >>> to appear in the scansion, denoting a triple outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 3 'Hopkins's diacritics: Let FirstOutride = 1 Let LastOutride = 3 GoSub ScanIO_OutrideDiacriticEvaluation GoSub ScanIO_InstallAndTransmit GoSub ScanIO_RestoreValues End If 'Are the requirements for triple outride met? End If 'Are there at least four syllables left? '3 syllables: trisyllabic resolved outride. If SyllablesLeft >= 3 Then If ResolvedTripleOutrideOk(LocalPrecedingStress, LocalPrecedingJuncture, _ LocalStress(1), LocalJuncture(1), LocalWeight(1), _ LocalStress(2), LocalJuncture(2), LocalWeight(2), _ LocalStress(3), LocalJuncture(3), LocalWeight(3)) Then Let ShiftInterval = 4 'Assess penalties for *Outride, *Resolved Outride, and *Trisyllabic Resolution. Let TransmittedViolationVector(n("Outride")) = LocalViolationVector(n("Outride")) + 1 Let TransmittedViolationVector(n("ResolOutR")) = LocalViolationVector(n("ResolOutR")) + 1 Let TransmittedViolationVector(n("TriResol")) = LocalViolationVector(n("TriResol")) + 1 'Assess a penalty for *Outride3 and *Outride4 if appropriate. Select Case OutrideJunctureStatus(LocalJuncture(3)) Case mMarginal Let TransmittedViolationVector(n("Outride3")) = LocalViolationVector(n("Outride3")) + 1 Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 Case mNotQuiteRight Let TransmittedViolationVector(n("Outride4")) = LocalViolationVector(n("Outride4")) + 1 End Select 'Assess penalty for line-initial outride Let TransmittedViolationVector(n("LineInitOutR")) = LocalViolationVector(n("LineInitOutR")) + 1 'Assess penalties for outrides in short lines. GoSub ScanIO_PenalizeOutridesInShortLines 'Cause >>> to appear in the scansion, denoting an outride. (Hopkins's mark is translated as "O"). Let OutrideCount = 3 'Hopkins's diacritics: Let FirstOutride = 2 Let LastOutride = 4 GoSub ScanIO_OutrideDiacriticEvaluation GoSub ScanIO_InstallAndTransmit GoSub ScanIO_RestoreValues End If 'Are the requirements for a trisyllabic resolved outride met? End If 'Are there at least four syllables left? 'Any circumstances at all: don't bother. ' I.e., just move on to ScanW() without seeking an initial outride. Let ShiftInterval = 0 GoSub ScanIO_InstallAndTransmit Exit Sub '------------------------------------------------------------------------------------------------------------------------------------------------------ ScanIO_PenalizeOutridesInShortLines: 'Assess penalties for outrides in short lines. If LineLongEnoughForOutride = False Then If SyllablesLeft = ShiftInterval Then 'Final, probably pretty harmless: Let TransmittedViolationVector(n("FinOutRShortLine")) = LocalViolationVector(n("FinOutRShortLine")) + 1 Else 'Non-final, pernicious: Let TransmittedViolationVector(n("OutRShortLine")) = LocalViolationVector(n("OutRShortLine")) + 1 End If End If Return '------------------------------------------------------------------------------------------------------------------------------------------------------ ScanIO_OutrideDiacriticEvaluation: For DiacriticIndex = FirstOutride To LastOutride 'Record incompatibility if you have made into an outride a syllables marked for S or W. Select Case LocalDiacritic(DiacriticIndex) Case mW, mS TransmittedViolationVector(n("HopIncompatO")) = TransmittedViolationVector(n("HopIncompatO")) + 1 End Select 'Record lack of support if you have made into an outride a syllable not diacritically marked for this purpose. If LocalDiacritic(DiacriticIndex) <> mO Then TransmittedViolationVector(n("HopNoSupport")) = TransmittedViolationVector(n("HopNoSupport")) + 1 End If 'Outrides cannot rhyme. Note that the rhyme diacritic will only occur once per line, so no need to accumulate violations. If LocalRhyme(DiacriticIndex) Then Let TransmittedViolationVector(n("HopRhyme")) = LocalViolationVector(n("HopRhyme")) + 1 End If 'Diacritic for caesura. It must divide the line evenly. Note that the caesura diacritic will only occur once per line, so no need to accumulate violations. If LocalCaesura(DiacriticIndex) Then If SPositionsLeft <> mNumberOfSPositions(LineIndex) / 2 Then Let TransmittedViolationVector(n("HopCaes")) = LocalViolationVector(n("HopCaes")) + 1 End If End If Next DiacriticIndex Return '------------------------------------------------------------------------------------------------------------------------------------------------------ ScanIO_InstallAndTransmit: 'You've created and suitably penalized a scansion for this position. Now record it and transmit ' it onward for scansion of the next position. 'Keep track of what's left to do: Let TransmittedSyllablesLeft = SyllablesLeft - ShiftInterval Let TransmittedSPositionsLeft = SPositionsLeft 'Add the newly scanned syllables, with their word affiliations, to the scansion in progress: Let TransmittedScansionSoFar = ScansionSoFar + Chr(9) Let TransmittedWordAffiliationSoFar = WordAffiliationSoFar + Chr(9) ' Stop For NewSyllableIndex = 1 To ShiftInterval Let TransmittedScansionSoFar = TransmittedScansionSoFar + " " + LocalSyllable(NewSyllableIndex) Let TransmittedWordAffiliationSoFar = TransmittedWordAffiliationSoFar + " " + LocalWords(NewSyllableIndex) Next NewSyllableIndex ' Stop 'Add diacritics to show how many outride syllables are present: For OutrideIndex = 1 To OutrideCount Let TransmittedScansionSoFar = TransmittedScansionSoFar + ">" Next OutrideIndex 'If user asked for it, report progress to the verbose output file: If mVerboseOutputFlag = True Then Let MyCost = ScansionCost(TransmittedViolationVector()) Print #mVerboseOutFile, MyCost; Chr(9); TransmittedScansionSoFar End If 'Keep scanning. 'Slide everything over: For SyllableIndex = 1 To SyllablesLeft - ShiftInterval Let TransmittedSyllable(SyllableIndex) = LocalSyllable(SyllableIndex + ShiftInterval) Let TransmittedWeight(SyllableIndex) = LocalWeight(SyllableIndex + ShiftInterval) Let TransmittedStress(SyllableIndex) = LocalStress(SyllableIndex + ShiftInterval) Let TransmittedJuncture(SyllableIndex) = LocalJuncture(SyllableIndex + ShiftInterval) Let TransmittedWords(SyllableIndex) = LocalWords(SyllableIndex + ShiftInterval) Let TransmittedOverriven(SyllableIndex) = LocalOverriven(SyllableIndex + ShiftInterval) Let TransmittedDiacritic(SyllableIndex) = LocalDiacritic(SyllableIndex + ShiftInterval) Let TransmittedRhyme(SyllableIndex) = LocalRhyme(SyllableIndex + ShiftInterval) Let TransmittedCaesura(SyllableIndex) = LocalCaesura(SyllableIndex + ShiftInterval) Next SyllableIndex 'What is the preceding stress for the next syllable? If ShiftInterval = 0 Then 'Nothing happened, so just copy what you have. Let TransmittedPrecedingStress = LocalPrecedingStress Let TransmittedPrecedingJuncture = LocalPrecedingJuncture Let TransmittedPrecedingWeight = LocalPrecedingWeight Else Let TransmittedPrecedingStress = LocalStress(ShiftInterval) Let TransmittedPrecedingJuncture = LocalJuncture(ShiftInterval) Let TransmittedPrecedingWeight = LocalWeight(ShiftInterval) End If 'Now that you've dealt with initial outrides, you can call the scansion routine for the ' line-initial W position: 'If you found an outride, you're no longer line-initial. If ShiftInterval = 0 Then Let TransmittedInversionOk = InversionOK Else Let TransmittedInversionOk = False End If ' The last two arguments are, InversionOk and LineInitial, never relevant except line-initially. Call ScanW(LineIndex, PrintIndex, TransmittedSyllablesLeft, TransmittedSPositionsLeft, TransmittedScansionSoFar, TransmittedWordAffiliationSoFar, TransmittedSyllable(), _ TransmittedWeight(), TransmittedPrecedingWeight, _ TransmittedStress(), TransmittedPrecedingStress, _ TransmittedJuncture(), TransmittedPrecedingJuncture, _ TransmittedWords(), _ TransmittedOverriven(), _ TransmittedDiacritic(), TransmittedRhyme(), TransmittedCaesura(), _ TransmittedViolationVector(), _ False, False, LineLongEnoughForOutride, NoOverreaving, PrintMe) Return '---------------------------------------------------------------------------------------------------------------------------------------------------------------- ScanIO_RestoreValues: 'Restore values. For ConstraintIndex = 1 To mNumberOfConstraints Let TransmittedViolationVector(ConstraintIndex) = LocalViolationVector(ConstraintIndex) Next ConstraintIndex Let OutrideCount = 0 Return End Sub Function OutrideJunctureStatus(MyJuncture As Long) As Long 'Establish whether having an outride is good, marginal, or bad. Select Case MyJuncture Case Is < 3 Let OutrideJunctureStatus = mBad Case 3 Let OutrideJunctureStatus = mMarginal Case 4 Let OutrideJunctureStatus = mNotQuiteRight Case Else Let OutrideJunctureStatus = mPerfect End Select End Function Function DisyllabicResolutionOk(Stress1 As Long, Stress2 As Long, _ Juncture1 As Long, _ Weight1 As String, Weight2 As String) As Boolean 'Evaluate whether two syllables can form a disyllabic resolution. ' We are going with a slightly stronger version than Kiparsky, in which the syllables must be in the same ' simplex word. Thus, prepositional phrases like 'to us cannot Resolve, and thus we predict you could ' not have a sequence like /W to us. Then /. ' Hard to make this truly empirical, since function words are so easily made stressless. 'The first syllable of a resolution must be light and stressed. If Weight1 = "v" Or Weight1 = "x" Then If Stress1 > 1 Then 'The sequence must be word-internal. If Juncture1 = 1 Then 'The next syllable must be stressless and non-heavy. If Stress2 = 1 Then If Weight2 = "v" Or Weight2 = "x" Then Let DisyllabicResolutionOk = True Exit Function End If 'Is the second syllable non-heavy? End If 'Is the second syllable stressless? End If 'Is the sequence word-internal? End If 'Is first syllable stressed? End If 'Is first syllable light? 'Default is false. Let DisyllabicResolutionOk = False End Function Function TrisyllabicResolutionOk(Stress1 As Long, Stress2 As Long, Stress3 As Long, _ Juncture1 As Long, Juncture2 As Long, Juncture3 As Long, _ Weight1 As String, Weight2 As String, Weight3 As String) As Boolean 'Evaluate whether three syllables can form a trisyllabic resolution. 'We're toying with the idea of not allowing this at all. There are so few lines were it is needed. If chkPermitTrisyllabicResolution.Value <> vbChecked Then Let TrisyllabicResolutionOk = False Exit Function End If 'The first syllable of a resolution must be (at least potentially) light and stressed. If Weight1 = "v" Or Weight1 = "x" Then If Stress1 > 1 Then 'The next two syllables must be stressless and non-heavy. We'll also assume, since this is the strictest hypothesis, that ' trisyllabic Resolution is word-bounded. (This assumption was unnecessary to state for disyllabic Resolution, since ' there are no stressed light syllables in English that are word-final.) 'The sequence must be word-internal. If Juncture1 = 1 Then If Stress2 = 1 Then If Juncture2 = 1 Then If Weight2 = "v" Or Weight2 = "x" Then If Stress3 = 1 Then If Weight3 = "v" Or Weight3 = "x" Then Let TrisyllabicResolutionOk = True Exit Function End If 'Is the third syllable non-heavy? End If 'Is the third syllable stressless? End If 'Is the second syllable non-heavy? End If 'Is the second syllable non-word-final? End If 'Is the second syllable stressless? End If 'Is the first syllable non-word-final? End If 'Is first syllable stressed? End If 'Is first syllable light or ambiguous? Let TrisyllabicResolutionOk = False End Function Function SingleOutrideOk(HeadStress As Long, HeadJuncture As Long, OutrideStress As Long, OutrideJuncture As Long) As Boolean 'where "head" is the first syllable occupying the preceding S position. 'Falling stress is required. If HeadStress > OutrideStress Then 'Evaluate juncture of final syllable. If OutrideJunctureStatus(OutrideJuncture) <> mBad Then 'NEW: Impose tighter juncture within the S + Outride unit. If HeadJuncture < OutrideJuncture Then Let SingleOutrideOk = True End If 'Is juncture tight within the outride? End If 'Is there enough of a juncture at the end of the outride? End If 'Is the falling-stress requirement met? End Function Function DoubleOutrideOk(HeadStress As Long, HeadJuncture As Long, _ Stress1 As Long, Juncture1 As Long, Weight1 As String, _ Stress2 As Long, Juncture2 As Long, Weight2 As String) As Boolean 'where "head" is the first syllable occupying the preceding S position. '1 and 2 represent the first and second syllables of the outride. 'The head syllable must be stressed (in order to produce a stress fall) If HeadStress > 1 Then 'In a disyllabic outride, only stressless syllables may occur. If Stress1 = 1 And Stress2 = 1 Then 'These syllables must be light or ambiguous. If Weight1 <> "-" And Weight2 <> "-" Then 'Evaluate juncture of final syllable. If OutrideJunctureStatus(Juncture2) <> mBad Then 'NEW: Impose tighter juncture within the S + Outride unit. If HeadJuncture < Juncture2 And Juncture1 < Juncture2 Then Let DoubleOutrideOk = True End If 'Is juncture tight within the outride? End If 'Is there enough of a juncture? End If 'Is the weight requirement on the members of the outride met? End If 'Is the stress requirement on the members of the outride met? End If 'Is the stress requirement on the head syllable met? End Function Function TripleOutrideOk(HeadStress As Long, HeadJuncture As Long, _ Stress1 As Long, Juncture1 As Long, Weight1 As String, _ Stress2 As Long, Juncture2 As Long, Weight2 As String, _ Stress3 As Long, Juncture3 As Long, Weight3 As String) As Boolean 'where "head" is the first syllable occupying the preceding S position. '1, 2 and 3 represent the first, second, and third syllables of the outride. 'The head syllable must be stressed (in order to produce a stress fall) If HeadStress > 1 Then 'In a trisyllabic outride, only stressless syllables may occur. If Stress1 = 1 And Stress2 = 1 And Stress3 = 1 Then 'These syllables must be light or ambiguous. If Weight1 <> "-" And Weight2 <> "-" And Weight3 <> "-" Then 'Evaluate juncture of final syllable. If OutrideJunctureStatus(Juncture3) <> mBad Then 'NEW: Impose tighter juncture within the S + Outride unit. If HeadJuncture < Juncture3 And Juncture1 < Juncture3 And Juncture2 < Juncture3 Then Let TripleOutrideOk = True End If 'Is juncture tight within the outride? End If 'Is there enough of a juncture? End If 'Is the weight requirement on the members of the outride met? End If 'Is the stress requirement on the members of the outride met? End If 'Is the stress requirement on the head syllable met? End Function Function ResolvedOutrideOk(HeadStress As Long, HeadJuncture As Long, _ Stress1 As Long, Juncture1 As Long, Weight1 As String, _ Stress2 As Long, Juncture2 As Long, Weight2 As String) As Boolean 'where "head" is the first syllable occupying the preceding S position. '1 and 2 represent the first and second syllables of the outride. 'There must be a stress fall between the head syllable and the first syllable of the outride. If HeadStress > Stress1 Then 'The first resolved syllable must be stressed and non-heavy. If Stress1 > 1 And Weight1 <> "-" Then 'The first resolve syllable must be (we believe) non-word-final If Juncture1 = 1 Then 'The second must be stressless and non-heavy. If Stress2 = 1 And Weight2 <> "-" Then 'Evaluate juncture of final syllable. If OutrideJunctureStatus(Juncture2) <> mBad Then 'NEW: Impose tighter juncture within the S + Outride unit. If HeadJuncture < Juncture2 And Juncture1 < Juncture2 Then Let ResolvedOutrideOk = True End If 'Is juncture tight within the outride? End If 'Is there enough of a juncture at the end of the outride? End If 'Are the stress and weight requirements on the second member of the outride met? End If 'Is the juncture requirement on the first member of the outride met? End If 'Are the stress and weight requirements on the first member of the outride met? End If 'Is the stress fall after the the head syllable present? End Function Function ResolvedTripleOutrideOk(HeadStress As Long, HeadJuncture As Long, _ Stress1 As Long, Juncture1 As Long, Weight1 As String, _ Stress2 As Long, Juncture2 As Long, Weight2 As String, _ Stress3 As Long, Juncture3 As Long, Weight3 As String) As Boolean '"Head" is the first syllable occupying the preceding S position. '1, 2, and 3 represent the first, second and third syllables of the outride. 'We're toying with the idea of not allowing this at all. There are so few lines were it is needed. If chkPermitTrisyllabicResolution.Value <> vbChecked Then Let ResolvedTripleOutrideOk = False Exit Function End If 'There must be a stress fall between the head syllable and the first syllable of the outride. If HeadStress > Stress1 Then 'The first resolved syllable must be stressed and non-heavy. If Stress1 > 1 And Weight1 <> "-" Then 'The second must be stressless and non-heavy. If Stress2 = 1 And Weight2 <> "-" Then 'The third must be stressless and non-heavy. If Stress3 = 1 And Weight3 <> "-" Then 'Evaluate juncture of final syllable. If OutrideJunctureStatus(Juncture3) <> mBad Then 'NEW: Impose tighter juncture within the S + Outride unit. If HeadJuncture < Juncture3 And Juncture1 < Juncture3 And Juncture2 < Juncture3 Then Let ResolvedTripleOutrideOk = True End If 'Is juncture tight within the outride? End If 'Is there enough of a juncture at the end of the outride? End If 'Are the stress and weight requirements on the third member of the outride met? End If 'Are the stress and weight requirements on the second member of the outride met? End If 'Are the stress and weight requirements on the first member of the outride met? End If 'Is the stress fall after the the head syllable present? End Function Sub PrintOutAScansion(PrintIndex As Long, MyCost As Single, TransmittedScansionSoFar As String, TransmittedWordAffilationSoFar As String, _ TransmittedViolationVector() As Long, LineIndex As Long, Source As String) 'Print out a particular scansion, both to the main output file and to the OTSoft file. 'This identifies scansions purely as scansions, stripping away Hopkins's diacritics. ' It is used to remove duplicate scansions when there are multiple codings of the line in the input file. Dim ScansionIdentifier As String 'This identifies scansions as a single, slash-delimited string, for human use. It includes the diacritics. Dim ScansionAsCompactFormula As String 'Ditto, but tab separated for spreadsheet display. Dim ScansionAsTabbedFormula As String 'This displays the words to which the syllables belong. Dim WordContentAsCompactFormula As String 'Temporarily store information in local variables for clarity. Dim SyllableBuffer As String, WordBuffer As String, ViolationVector As String Dim MyHopkinsScore As Single Dim MySyllables As String, MyWords As String Dim FootIndex As Long, ConstraintIndex As Long 'Make little formulae to display the candidate: one with / and positions labels, the other with tabs. 'The TransmittedScansionSoFar with which we are working always begins with a tab, since it's grown by accreting tab + syllables. Let SyllableBuffer = s.Residue(TransmittedScansionSoFar) Let WordBuffer = s.Residue(TransmittedWordAffilationSoFar) 'Begin with the initial outride position, if filled, else it will be null (as a newly-initialized local variable): Let MySyllables = TrimAbbreviations(s.Chomp(SyllableBuffer)) Let MyWords = s.Chomp(WordBuffer) If Trim(MySyllables) <> "()" Then Let ScansionAsCompactFormula = " /O " + MySyllables Let ScansionAsTabbedFormula = MySyllables Let ScansionIdentifier = " /O " + DeleteAbbreviations(s.Chomp(SyllableBuffer)) Let WordContentAsCompactFormula = " /O " + MyWords End If 'The other syllables: Do Let SyllableBuffer = s.Residue(SyllableBuffer) If Trim(SyllableBuffer) = "" Then Exit Do Let WordBuffer = s.Residue(WordBuffer) 'W position: Let MySyllables = TrimAbbreviations(s.Chomp(SyllableBuffer)) Let MyWords = s.Chomp(WordBuffer) Let ScansionAsCompactFormula = ScansionAsCompactFormula + " /W " + MySyllables Let ScansionAsTabbedFormula = ScansionAsTabbedFormula + Chr(9) + MySyllables Let ScansionIdentifier = ScansionIdentifier + " /W " + DeleteAbbreviations(s.Chomp(SyllableBuffer)) Let WordContentAsCompactFormula = WordContentAsCompactFormula + " /W " + MyWords 'Move onward, exiting if appropriate: Let SyllableBuffer = s.Residue(SyllableBuffer) If Trim(SyllableBuffer) = "" Then Exit Do Let WordBuffer = s.Residue(WordBuffer) 'S position: Let MySyllables = TrimAbbreviations(TrimAbbreviations(s.Chomp(SyllableBuffer))) Let MyWords = s.Chomp(WordBuffer) Let ScansionAsCompactFormula = ScansionAsCompactFormula + " /S " + MySyllables Let ScansionAsTabbedFormula = ScansionAsTabbedFormula + Chr(9) + MySyllables Let ScansionIdentifier = ScansionIdentifier + " /S " + DeleteAbbreviations(s.Chomp(SyllableBuffer)) Let WordContentAsCompactFormula = WordContentAsCompactFormula + " /S " + MyWords Loop 'Remove any extraneous spaces: Let ScansionAsCompactFormula = Trim(ScansionAsCompactFormula) Let ScansionIdentifier = Trim(ScansionIdentifier) Let WordContentAsCompactFormula = Trim(WordContentAsCompactFormula) 'If the user has checked the appropriate box, then print only if the scansion is unique. ' Nonunique scansions arise when there are different versions of the line in the input file. If chkRemoveDuplicateScansions.Value <> vbChecked Or UniqueScansion(ScansionIdentifier) Then 'The main output file: 'First, a number to help in sorting: 10 times the line number. ' Note: this one is actually the PrintIndex, to permit the extra scansions from overreaving to be entered. Print #mOutFile, LTrim(Str(10 * PrintIndex)); 'Then the cost and scansion. Print #mOutFile, Chr(9); MyCost; Chr(9); ScansionAsTabbedFormula; 'Print enough tabs to align what follows. For FootIndex = mNumberOfSPositions(LineIndex) + 1 To mDefaultNumberOfSPositions Print #mOutFile, Chr(9); Chr(9); Next FootIndex 'If you ended in S position, add a tab so that all will line up. If Source = "S" Then Print #mOutFile, Chr(9); End If 'Print the violations. Print #mOutFile, Chr(9); Chr(9); For ConstraintIndex = 1 To mNumberOfConstraints Print #mOutFile, Chr(9); TransmittedViolationVector(ConstraintIndex); Next ConstraintIndex 'And the brief encoding: debug, include the word affiliations. Print #mOutFile, Chr(9); ScansionAsCompactFormula; Chr(9); WordContentAsCompactFormula 'Record material for the OTSoft file, which gets recorded later: 'Record information if it's a new line. It's not a new line if it's non-initial in a pool. Let mNumberOfOTSoftInputs = mAffiliatedTypizedLineIndex(LineIndex) Let mOTSoftInputs(mNumberOfOTSoftInputs) = mFullText(LineIndex) 'End If 'Record information about this candidate. Let mNumberOfOTSoftCandidates(mNumberOfOTSoftInputs) = mNumberOfOTSoftCandidates(mNumberOfOTSoftInputs) + 1 Let mOTSoftCandidates(mNumberOfOTSoftInputs, mNumberOfOTSoftCandidates(mNumberOfOTSoftInputs)) = ScansionAsCompactFormula Let mOTSoftWordAffiliations(mNumberOfOTSoftInputs, mNumberOfOTSoftCandidates(mNumberOfOTSoftInputs)) = WordContentAsCompactFormula 'Create the violation vector and record it. For ConstraintIndex = 1 To mNumberOfConstraints 'Ignore cancelled and inviolable constraints, which are of no interest in a learning file. If Not mCancelledConstraint(ConstraintIndex) Then If Not mInviolableConstraint(ConstraintIndex) Then Let ViolationVector = ViolationVector + Chr(9) + s.ZeroIsBlank(TransmittedViolationVector(ConstraintIndex)) End If End If Next ConstraintIndex 'Trim back the initial tab. Let ViolationVector = s.Residue(ViolationVector) Let mOTSoftViolationVector(mNumberOfOTSoftInputs, mNumberOfOTSoftCandidates(mNumberOfOTSoftInputs)) = ViolationVector 'Compute the "Hopkins score"; i.e a metric of conformity with Hopkins's diacritics. ' This is one point for each outright contradiction of a Hopkins diacritic, plus a tenth of a point for an outride not marked by ' Hopkins. Let MyHopkinsScore = MyHopkinsScore + TransmittedViolationVector(n("HopIncompatS")) Let MyHopkinsScore = MyHopkinsScore + TransmittedViolationVector(n("HopIncompatW")) Let MyHopkinsScore = MyHopkinsScore + TransmittedViolationVector(n("HopIncompatO")) Let MyHopkinsScore = MyHopkinsScore + TransmittedViolationVector(n("HopRhyme")) Let MyHopkinsScore = MyHopkinsScore + TransmittedViolationVector(n("HopCaes")) Let MyHopkinsScore = MyHopkinsScore + 0.1 * TransmittedViolationVector(n("HopNoSupport")) 'Provisional code, now commented out: include the ban on light syllables in S, under the view that Hopkins resolves whenever ' he can. I think this should probably go. ' Let MyHopkinsScore = MyHopkinsScore + 0.01 * TransmittedViolationVector(n("LightInS")) Let mOTSoftHopkinsScores(mNumberOfOTSoftInputs, mNumberOfOTSoftCandidates(mNumberOfOTSoftInputs)) = MyHopkinsScore End If 'Is this scansion unique? End Sub Function UniqueScansion(MyScansion As String) As Boolean 'Check a scansion and return True if it's not already on the list. Also, add it to the list. Dim ScansionIndex As Long For ScansionIndex = 1 To mTotalNumberOfScansions If MyScansion = mTotalScansions(ScansionIndex) Then 'It's not new. Let UniqueScansion = False Exit Function End If Next ScansionIndex 'It's new, so record true and remember it. Let UniqueScansion = True Let mTotalNumberOfScansions = mTotalNumberOfScansions + 1 ReDim Preserve mTotalScansions(mTotalNumberOfScansions) Let mTotalScansions(mTotalNumberOfScansions) = MyScansion End Function Function TrimAbbreviations(MyString As String) As String 'The diacritic spellouts make candidate scansions a bit hard to read (they need to be long, to be unambiguous). 'So re-abbreviate them, staying within the limits of ASCII. Let MyString = Trim(MyString) If MyString = "" Then Let TrimAbbreviations = "()" Else Let MyString = Replace(MyString, "RHYME", "RH") Let MyString = Replace(MyString, "SGAC", ">") Let MyString = Replace(MyString, "DBAC", ">") Let MyString = Replace(MyString, "OUTR", "O") Let MyString = Replace(MyString, "DGRV", Chr(96)) Let MyString = Replace(MyString, "GCS", "::") Let TrimAbbreviations = MyString End If End Function Function DeleteAbbreviations(MyString As String) As String 'The diacritic spellouts sometimes differ multiple codings of the same input candidates. ' But we want to count them as the same scansion for purposes of removing duplications. ' So just delete them. Let MyString = Trim(MyString) If MyString = "" Then Let DeleteAbbreviations = "()" Else Let MyString = Replace(MyString, "RHYME", "") Let MyString = Replace(MyString, "SGAC", "") Let MyString = Replace(MyString, "DBAC", "") Let MyString = Replace(MyString, "OUTR", "") Let MyString = Replace(MyString, "DGRV", "") Let MyString = Replace(MyString, "GCS", "") Let DeleteAbbreviations = MyString End If End Function Sub SortOutputFile() Dim InFile As Long, OutFile As Long Dim Lines() As String Dim Sorter() As Long Dim InnerSorter() As Single Dim MyLine As String Dim NumberOfLines As Long Dim LineCatcher As Long, LineIndex As Long, ViolationCount As Long Dim SwapLong As Long, SwapSingle As Single, SwapString As String Dim OuterSortingIndex As Long, InnerSortingIndex As Long Dim CurrentLine As String, LocalBestValue As Long 'Report progress Let cmdGo.Caption = "Sorting ..." Close 'Read the file: Let InFile = FreeFile Open App.Path + "/output/Outputfor" + txtFilename.Text For Input As #InFile Do While Not EOF(1) Line Input #InFile, MyLine Let NumberOfLines = NumberOfLines + 1 ReDim Preserve Lines(NumberOfLines) Let Lines(NumberOfLines) = s.Residue(MyLine) ReDim Preserve Sorter(NumberOfLines) Let Sorter(NumberOfLines) = Val(Trim(s.Chomp(MyLine))) ReDim Preserve InnerSorter(NumberOfLines) Let InnerSorter(NumberOfLines) = Val(Trim(s.Chomp(s.Residue(MyLine)))) Loop Close #InFile 'Sort: For OuterSortingIndex = 1 To NumberOfLines For InnerSortingIndex = 1 To OuterSortingIndex - 1 'Sort by first column, else by second. If Sorter(OuterSortingIndex) < Sorter(InnerSortingIndex) _ Or (Sorter(OuterSortingIndex) = Sorter(InnerSortingIndex) And InnerSorter(OuterSortingIndex) < InnerSorter(InnerSortingIndex)) Then Let SwapLong = Sorter(OuterSortingIndex) Let Sorter(OuterSortingIndex) = Sorter(InnerSortingIndex) Let Sorter(InnerSortingIndex) = SwapLong Let SwapSingle = InnerSorter(OuterSortingIndex) Let InnerSorter(OuterSortingIndex) = InnerSorter(InnerSortingIndex) Let InnerSorter(InnerSortingIndex) = SwapSingle Let SwapString = Lines(OuterSortingIndex) Let Lines(OuterSortingIndex) = Lines(InnerSortingIndex) Let Lines(InnerSortingIndex) = SwapString End If Next InnerSortingIndex Next OuterSortingIndex 'Print: Let OutFile = FreeFile 'Use this one for debugging; it doesn't overwrite the original: 'Open App.Path + "/output/SortedOutputfor" + txtFilename.Text For Output As #OutFile Open App.Path + "/output/Outputfor" + txtFilename.Text For Output As #OutFile For LineIndex = 1 To NumberOfLines Print #OutFile, Lines(LineIndex) Next LineIndex Close #OutFile End Sub Sub PrintProsodicAnnotations(LineIndex As Long, PrintIndex As Long, NumberOfSyllables As Long, _ Syllables() As String, Stress() As Long, Juncture() As Long, WordMembership() As String, Weight() As String) Dim SyllableIndex As Long 'Print the syllables, stresses, junctures, weights. Call PrintSpacer(LineIndex, PrintIndex) Print #mOutFile, "1Syllables"; Chr(9); mFullText(LineIndex); For SyllableIndex = 1 To NumberOfSyllables Print #mOutFile, Chr(9); Syllables(SyllableIndex); Next SyllableIndex Print #mOutFile, Call PrintSpacer(LineIndex, PrintIndex) Print #mOutFile, "2Stress"; Chr(9); mFullText(LineIndex); For SyllableIndex = 1 To NumberOfSyllables Print #mOutFile, Chr(9); "s"; Trim(Str(Stress(SyllableIndex))); Next SyllableIndex Print #mOutFile, Call PrintSpacer(LineIndex, PrintIndex) Print #mOutFile, "3Juncture"; Chr(9); mFullText(LineIndex); For SyllableIndex = 1 To NumberOfSyllables Print #mOutFile, Chr(9); "j"; Trim(Str(Juncture(SyllableIndex))); Next SyllableIndex Print #mOutFile, Call PrintSpacer(LineIndex, PrintIndex) Print #mOutFile, "4Weight"; Chr(9); mFullText(LineIndex); For SyllableIndex = 1 To NumberOfSyllables Print #mOutFile, Chr(9); Weight(SyllableIndex); Next SyllableIndex Print #mOutFile, Call PrintSpacer(LineIndex, PrintIndex) Print #mOutFile, "5Words"; Chr(9); mFullText(LineIndex); For SyllableIndex = 1 To NumberOfSyllables Print #mOutFile, Chr(9); WordMembership(SyllableIndex); Next SyllableIndex Print #mOutFile, Call PrintSpacer(LineIndex, PrintIndex) Print #mOutFile, "6Annotation"; Chr(9); mFullText(LineIndex); Print #mOutFile, Chr(9); mAnnotation(LineIndex) End Sub Sub PrintSpacer(LineIndex As Long, PrintIndex As Long) Dim i 'Print a sorting device. Print #mOutFile, Trim(Str(10 * PrintIndex + 1)); 'Print enough tabs. For i = 1 To mOutFile * mDefaultNumberOfSPositions + 4 Print #mOutFile, Chr(9); Next i 'Print the line index, to allow extraction. Print twice, once for sorting, once to preserve the input file format. If LineIndex = 0 Then Print #mOutFile, Trim(Str(LineIndex)); Chr(9); Else Print #mOutFile, Trim(Str(LineIndex)); Chr(9); Trim(Str(LineIndex)); Chr(9); End If End Sub Sub PrintOTSoftFile() 'The idea is to use Hopkins's diacritic markings to indicate which scansion he preferred. ' This is done with a score, already computed in PrintOutAScansion(). 'The file to be printed will have extra columns, to permit inspection: ' Line number ' Input repeated for every candidate. ' The violations of the Hopkins diacritic-matching constraints, which are not part of the grammar (else circular). 'These columns must be deleted before running the maxent software. 'On Error GoTo ErrorPoint Dim OTSoftFile As Long, FileBeingOpened As String Dim BestScoreSoFar As Single, BestScoreBearer As Long Dim LabelThisOne() As Long ReDim LabelThisOne(mNumberOfOTSoftInputs) Dim Tied As Boolean Dim OTSoftWinner() As Long ReDim OTSoftWinner(mNumberOfOTSoftInputs) 'Variables for harmonic bounding. Dim WinnerVector As String, RivalVector As String Dim LineIndex As Long, CandidateIndex As Long, ConstraintIndex As Long, RowIndex As Long, OTSoftInputIndex As Long Dim TypizedLineIndex As Long 'Report progress. Let cmdGo.Caption = "Creating OTSoft file ..." 'Compute the winner, if any, for each line. There is no winner when there are ties. For LineIndex = 1 To mNumberOfLines 'This works in the typized domain, where multiple pooled inputs are represented by one index. ' This is a fertile source of bugs. Let TypizedLineIndex = mAffiliatedTypizedLineIndex(LineIndex) 'Search for the best score: Let BestScoreSoFar = 1000 For CandidateIndex = 1 To mNumberOfOTSoftCandidates(TypizedLineIndex) 'It's not a real candidate if it would induce an overreaving violation in the next line. If mFinalPositionMustBeEmpty(TypizedLineIndex) Then 'The overreaving violation is created by a filled final W position: If EndsInFilledW(mOTSoftCandidates(TypizedLineIndex, CandidateIndex)) Then GoTo ExitPoint End If End If 'Even when there is no Hopkins winner, some line has to get the input label. If you've gotten this far, it ' might as well be you. If LabelThisOne(TypizedLineIndex) = 0 Then Let LabelThisOne(TypizedLineIndex) = CandidateIndex 'See if this one has the best score, and if so, if it is tied for best. If mOTSoftHopkinsScores(TypizedLineIndex, CandidateIndex) < BestScoreSoFar Then Let BestScoreSoFar = mOTSoftHopkinsScores(TypizedLineIndex, CandidateIndex) Let BestScoreBearer = CandidateIndex Let Tied = False ElseIf mOTSoftHopkinsScores(TypizedLineIndex, CandidateIndex) = BestScoreSoFar Then Let Tied = True End If ExitPoint: Next CandidateIndex 'To be a "Hopkins winner", you need to have no fatal mismatches (contradiction of Hopkins diacritic) ' and you must be better than all other candidates. If Tied = False Then If BestScoreSoFar < 1 Then Let OTSoftWinner(TypizedLineIndex) = BestScoreBearer 'Winners should bear the label if possible. Let LabelThisOne(TypizedLineIndex) = BestScoreBearer End If End If 'MsgBox "OTSoft winner for line " + Str(TypizedLineIndex) + " is " + Str(OTSoftWinner(TypizedLineIndex)) Next LineIndex 'Open the output file. Let OTSoftFile = FreeFile Let FileBeingOpened = App.Path + "/output/OTSoftFileFor" + txtFilename.Text Open FileBeingOpened For Output As #OTSoftFile 'Print a header. 'Constraint names, twice, plus label various other items, intended to help interpret the resulting grammar. ' The zero is to help sort this file when inspecting it. For RowIndex = 1 To 2 Print #OTSoftFile, "0"; Chr(9); Chr(9); Chr(9); For ConstraintIndex = 1 To mNumberOfConstraints 'Cancelled and inviolable constraints are not included in this file. If Not mCancelledConstraint(ConstraintIndex) Then If Not mInviolableConstraint(ConstraintIndex) Then Print #OTSoftFile, Chr(9); mConstraintNames(ConstraintIndex); End If End If Next ConstraintIndex 'An arbitrary-scale score; unique minima are taken to be Hopkins's preference. Print #OTSoftFile, Chr(9); "HopScore"; 'For sorting the output file: 1 if there is such a candidate for this input, else zero. Print #OTSoftFile, Chr(9); "HasHWinner"; 'Number of candidates -- helps in assessing the "scanning like slicing cucumbers" issue: Print #OTSoftFile, Chr(9); "No.Candidates"; 'Reciprocal of above, used for assessing performance of a nonstochastic version of the grammar: Print #OTSoftFile, Chr(9); "KScore"; 'The words to which the syllables belong. Print #OTSoftFile, Chr(9); "Word affiliations" Next RowIndex 'Loop through the lines (by type, not token) and print. For TypizedLineIndex = 1 To mNumberOfOTSoftInputs 'First, a line number: deleted in actual use, but perhaps useful in inspection. Print #OTSoftFile, Trim(Str(TypizedLineIndex)); 'Print the input Print #OTSoftFile, Chr(9); mOTSoftInputs(TypizedLineIndex); 'Print the candidate that is supposed to be labeled. 'First, vet this candidate for overreaving problems. If mFinalPositionMustBeEmpty(TypizedLineIndex) Then If EndsInFilledW(mOTSoftCandidates(TypizedLineIndex, LabelThisOne(TypizedLineIndex))) Then GoTo ExitPoint1 End If End If 'It passed the test, so print it. Print #OTSoftFile, Chr(9); mOTSoftCandidates(TypizedLineIndex, LabelThisOne(TypizedLineIndex)); 'Its status as winner, if appropriate: If LabelThisOne(TypizedLineIndex) = OTSoftWinner(TypizedLineIndex) Then Print #OTSoftFile, Chr(9); "1"; 'Check for harmonic bounding if desired. If chkHarmonicBounding.Value = vbChecked Then For CandidateIndex = 1 To mNumberOfOTSoftCandidates(TypizedLineIndex) 'Vet this candidate for overreaving problems. If Not mFinalPositionMustBeEmpty(TypizedLineIndex) Then 'You can't harmonically bound yourself. If CandidateIndex <> LabelThisOne(TypizedLineIndex) Then Let RivalVector = mOTSoftViolationVector(TypizedLineIndex, CandidateIndex) Let WinnerVector = mOTSoftViolationVector(TypizedLineIndex, OTSoftWinner(TypizedLineIndex)) If RivalBoundsWinner(RivalVector, WinnerVector) Then Print #OTSoftFile, "HB"; End If End If End If Next CandidateIndex End If 'Identify harmonically bounded winners, if the user so wishes. ' If chkHarmonicBounding.Value = vbChecked Then ' If WinnerIsHarmonicallyBounded(TypizedLineIndex, OTSoftWinner()) Then '' Print #OTSoftFile, "HB"; ' End If ' End If Else Print #OTSoftFile, Chr(9); End If 'The violations: Print #OTSoftFile, Chr(9); mOTSoftViolationVector(TypizedLineIndex, LabelThisOne(TypizedLineIndex)); 'Conclude with material for statistics and analysis. 'The Hopkins score. Print #OTSoftFile, Chr(9); Trim(Str(mOTSoftHopkinsScores(TypizedLineIndex, LabelThisOne(TypizedLineIndex)))); 'Whether this is a line that has a Hopkins winner. If OTSoftWinner(TypizedLineIndex) > 0 Then Print #OTSoftFile, Chr(9); 1; Else Print #OTSoftFile, Chr(9); 0; End If 'For computing "Kiparsky scores", it is useful to count the number of candidate scansions and the reciprocal. Print #OTSoftFile, Chr(9); mNumberOfOTSoftCandidates(TypizedLineIndex); If mNumberOfOTSoftCandidates(TypizedLineIndex) > 0 Then Print #OTSoftFile, Chr(9); 1 / mNumberOfOTSoftCandidates(TypizedLineIndex); End If 'The words to which the syllables belong -- used for checking how syllable weight works. Print #OTSoftFile, Chr(9); mOTSoftWordAffiliations(TypizedLineIndex, LabelThisOne(TypizedLineIndex)) ExitPoint1: 'Print the material for the remaining candidates For CandidateIndex = 1 To mNumberOfOTSoftCandidates(TypizedLineIndex) If CandidateIndex <> LabelThisOne(TypizedLineIndex) Then 'First, vet this candidate for overreaving problems. If mFinalPositionMustBeEmpty(TypizedLineIndex) Then 'MsgBox "The line " + mOTSoftInputs(TypizedLineIndex) + " must not be scanned with a filled final W position, else overreaving will be violated." If EndsInFilledW(mOTSoftCandidates(TypizedLineIndex, CandidateIndex)) Then GoTo ExitPoint2 End If End If 'It passed, so print it out. 'Print the index and fill in the space earlier occupied in this column by the input form. Print #OTSoftFile, Trim(Str(TypizedLineIndex)); Chr(9); 'Print the candidate. Print #OTSoftFile, Chr(9); mOTSoftCandidates(TypizedLineIndex, CandidateIndex); 'Its status as winner, if appropriate: If CandidateIndex = OTSoftWinner(TypizedLineIndex) Then Print #OTSoftFile, Chr(9); "1"; Else Print #OTSoftFile, Chr(9); End If 'If it harmonically bounds the winner, and the user so wishes, say so. If chkHarmonicBounding.Value = vbChecked Then If LabelThisOne(TypizedLineIndex) = OTSoftWinner(TypizedLineIndex) Then Let RivalVector = mOTSoftViolationVector(TypizedLineIndex, CandidateIndex) Let WinnerVector = mOTSoftViolationVector(TypizedLineIndex, OTSoftWinner(TypizedLineIndex)) If RivalBoundsWinner(RivalVector, WinnerVector) Then Print #OTSoftFile, "B"; End If End If End If 'The violations: Print #OTSoftFile, Chr(9); mOTSoftViolationVector(TypizedLineIndex, CandidateIndex); 'Conclude with material for statistics and analysis. 'The Hopkins score. Print #OTSoftFile, Chr(9); Trim(Str(mOTSoftHopkinsScores(TypizedLineIndex, CandidateIndex))); 'Whether this is a line that has a Hopkins winner. If OTSoftWinner(TypizedLineIndex) > 0 Then Print #OTSoftFile, Chr(9); 1; Else Print #OTSoftFile, Chr(9); 0; End If 'For computing "Kiparsky scores", it is useful to count the number of candidate scansions and the reciprocal. Print #OTSoftFile, Chr(9); mNumberOfOTSoftCandidates(TypizedLineIndex); If mNumberOfOTSoftCandidates(TypizedLineIndex) > 0 Then Print #OTSoftFile, Chr(9); 1 / mNumberOfOTSoftCandidates(TypizedLineIndex); End If 'Word affiliations of the syllables Print #OTSoftFile, Chr(9); mOTSoftWordAffiliations(TypizedLineIndex, CandidateIndex) End If 'Don't re-print the input-labeled candidate. ExitPoint2: Next CandidateIndex 'Loop through candidate for this input. Next TypizedLineIndex 'Loop through typized inputs. Close #OTSoftFile Exit Sub ErrorPoint: 'Let the user close an already-open output file without crashing. If Err.Number = 70 Then MsgBox "It appears that the file called " + FileBeingOpened + " is already open in some other program. Since I need to use this file, please close it in the other program, then click OK." Resume Else MsgBox "Fatal error. Please report this to xxx, specifying error #28945." End If End Sub Function EndsInFilledW(MyString As String) As Boolean 'We don't want to include in the OTSoft file any scansions that end in a filled W, when the following ' line needs the W to scan. Dim i As Long 'MsgBox MyString For i = Len(MyString) To 2 Step -1 Select Case Mid(MyString, i - 1, 2) Case "/S" Let EndsInFilledW = False Exit Function Case "/W" Let EndsInFilledW = True Exit Function End Select Next i Stop End Function Function WinnerIsHarmonicallyBounded(MyLineIndex, MyWinners() As Long) As Boolean 'If a winning candidate is harmonically bounded, returns "HB" plus the index of the bounder. Else returns null. Dim CandidateIndex As Long Dim PermanentWinnerVector As String, WinnerVector As String, RivalVector As String 'Violation vectors are tab-delimited strings. Let PermanentWinnerVector = mOTSoftViolationVector(MyLineIndex, MyWinners(MyLineIndex)) 'Examine every rival candidate. For CandidateIndex = 1 To mNumberOfOTSoftCandidates(MyLineIndex) 'Reinitialize. Let WinnerVector = PermanentWinnerVector 'Don't bother to check the winner against itself. If CandidateIndex <> MyWinners(MyLineIndex) Then Let RivalVector = mOTSoftViolationVector(MyLineIndex, CandidateIndex) If RivalBoundsWinner(RivalVector, WinnerVector) Then 'Record the fact, and the identity of the bounder, and get out.. Let WinnerIsHarmonicallyBounded = True Exit Function End If End If 'Don't check a winner against itself. Next CandidateIndex 'Examine every rival candidate. 'We went through all the rival candidates without finding a harmonic bounder, so do nothing; i.e. get out, returning null. End Function Function RivalBoundsWinner(MyRivalVector As String, MyWinnerVector As String) As Boolean Dim ConstraintIndex As Long Dim WinnerViols As Long, RivalViols As Long Dim HarmonicallyBoundedSoFar As Boolean 'Do a comparison for every relevant constraint. For ConstraintIndex = 1 To mNumberOfConstraints 'We need to consider only those constraints that are actually in the violation vector, and of ' these, only the relevant ones. If Not mCancelledConstraint(ConstraintIndex) Then 'Not in the vector, so don't chomp. If Not mInviolableConstraint(ConstraintIndex) Then 'Not in the vector, so don't chomp. 'Grab the violations by chomping the violation string. Let WinnerViols = Val(s.Chomp(MyWinnerVector)) Let RivalViols = Val(s.Chomp(MyRivalVector)) 'Prepare to grab the next value. Let MyWinnerVector = s.Residue(MyWinnerVector) Let MyRivalVector = s.Residue(MyRivalVector) If Not mHopkinsDiacriticConstraint(ConstraintIndex) Then 'Not relevant, so chomp but ignore. 'If the rival loses even once, it cannot be a harmonic bounder. If RivalViols > WinnerViols Then Let RivalBoundsWinner = False Exit Function 'If the winner loses once, then there is the possibility that it is harmonically bounded. ' But this could easily be overridden as we move through the other constraints. ElseIf WinnerViols > RivalViols Then Let HarmonicallyBoundedSoFar = True End If End If 'Only consider eligible constraints. End If 'Don't chomp inviolable constraint violations, there not there. End If 'Don't chomp candeled constraint violations, there not there. Next ConstraintIndex 'Loop through all constraints. 'Ok, we've checked all the constraints, and if we are in the "bounded" state, we've got bounding. If HarmonicallyBoundedSoFar = True Then Let RivalBoundsWinner = True Else Let RivalBoundsWinner = False End If End Function Function ScansionCost(MyViolations() As Long) As Single 'The cost of a scansion is the dot product of its violations and the weights. Dim ConstraintIndex As Long, Buffer As Single For ConstraintIndex = 1 To mNumberOfConstraints Let Buffer = Buffer + MyViolations(ConstraintIndex) * mCosts(ConstraintIndex) Next ConstraintIndex Let ScansionCost = Buffer End Function Function n(MyConstraintName As String) As Long 'To avoid programming error, let constraint names appear as names in the program. ' This function yields their position in the array. Dim i As Long 'Look for the constraint name in the grammar. For i = 1 To mNumberOfConstraints If mConstraintNames(i) = MyConstraintName Then Let n = i Exit Function End If Next i 'Couldn't find it, so fail informatively. MsgBox "The constraint name " + MyConstraintName + " is not recognized by the program. Please fix your file Grammar.txt before running again." Close End End Function Sub AnnounceCompletion() On Error GoTo ErrorPoint 'Time the program: Let TimeElapsed = Timer - TimeElapsed 'By relabeling the Go button: Let cmdGo.Caption = "Done! The run took " + Str(Int(TimeElapsed)) + " seconds. Click again to exit." 'By beeping, in longer files: If TimeElapsed > 20 Then Shell App.Path + "/beep.bat" End If ErrorPoint: Exit Sub End Sub Sub SetUpGrammar() 'Establish the number of constraints, the constraint names, and their weights, using the user-modifiable ' Grammar.txt file, kept in the Input folder. Dim c As Long 'Used to count the constraints as they are added. Dim ConstraintIndex As Long 'Variables for reading the Grammar.txt Dim GrammarFile As Long, MyLine As String, MyConstraint As String, MyUsage As String, MyWeight As Single 'Install the names. The violation patterns are in the routines ScanInitialOutride(), ScanW() and ScanS(). 'Constraints penalizing stress in W position. Let c = c + 1 Let mConstraintNames(c) = "StrInW" Let c = c + 1 Let mConstraintNames(c) = "MatchSW" Let c = c + 1 Let mConstraintNames(c) = "FinalFall" 'The following appear to be worthless (weighted at zero). But check again later. Let c = c + 1 Let mConstraintNames(c) = "StrongYouth4" Let c = c + 1 Let mConstraintNames(c) = "StrongYouth5" Let c = c + 1 Let mConstraintNames(c) = "TheLife4" Let c = c + 1 Let mConstraintNames(c) = "TheLife5" 'Defunct. Replaced by FinalFall. 'Let mConstraintNames(3) = "StrYouthFin" 'Constraints penalizing insufficiently robust S positions. Let c = c + 1 Let mConstraintNames(c) = "StrlsInS" Let c = c + 1 Let mConstraintNames(c) = "LightInS" 'Jespersenian constraint penalizing falling stress into S position. Let c = c + 1 Let mConstraintNames(c) = "MatchWS" 'Constraints regulating empty W. Let c = c + 1 Let mConstraintNames(c) = "EmptyW" Let c = c + 1 Let mConstraintNames(c) = "MedialEmptyW" Let c = c + 1 Let mConstraintNames(c) = "NoClashEmpW" Let c = c + 1 Let mConstraintNames(c) = "PostLEmpW" Let c = c + 1 Let mConstraintNames(c) = "Post1EmpW" Let c = c + 1 Let mConstraintNames(c) = "Post2EmpW" 'Constraints regulating resolution. Let c = c + 1 Let mConstraintNames(c) = "WResol" Let c = c + 1 Let mConstraintNames(c) = "SResol" Let c = c + 1 Let mConstraintNames(c) = "ResolOutR" Let c = c + 1 Let mConstraintNames(c) = "TriResol" 'Constraints regulating multiply-filled (not resolved) W positions. Let c = c + 1 Let mConstraintNames(c) = "2SylInW" Let c = c + 1 Let mConstraintNames(c) = "2SylInFinalW" Let c = c + 1 Let mConstraintNames(c) = "3SylInW" Let c = c + 1 Let mConstraintNames(c) = "4SylInW" Let c = c + 1 Let mConstraintNames(c) = "5SylInW" 'Constraints regulating outrides. Let c = c + 1 Let mConstraintNames(c) = "Outride" Let c = c + 1 Let mConstraintNames(c) = "DoubleOutR" Let c = c + 1 Let mConstraintNames(c) = "TripleOutR" Let c = c + 1 Let mConstraintNames(c) = "LineInitOutR" Let c = c + 1 Let mConstraintNames(c) = "OutRShortLine" 'These ban outrides without a good juncture to justify them. Let c = c + 1 Let mConstraintNames(c) = "Outride3" Let c = c + 1 Let mConstraintNames(c) = "Outride4" 'Bans a stressless, pre-[5 juncture] syllable that has no outride. Let c = c + 1 Let mConstraintNames(c) = "NoOutride5" 'Let mConstraintNames(23) = "1SylPhrOutr" 'This seems not to be necessary. 'Abandoned; we don't need this level of detail. 'Let mConstraintNames(22) = "FinOutRShortLine" 'Abandoned; we would need IPA to do this properly and this is not going to happen. 'Let mConstraintNames(23) = "Paraph" 'The remaining "constraints" are not part of the grammar, but are used for determining whether ' candidate scansions are compatible with Hopkins's diacritics. Let c = c + 1 Let mConstraintNames(c) = "HopNoSupport" Let c = c + 1 Let mConstraintNames(c) = "HopIncompatS" Let c = c + 1 Let mConstraintNames(c) = "HopIncompatW" Let c = c + 1 Let mConstraintNames(c) = "HopIncompatO" Let c = c + 1 Let mConstraintNames(c) = "HopRhyme" Let c = c + 1 Let mConstraintNames(c) = "HopCaes" 'Let mConstraintNames(35) = "Debug" 'Redim the cost array for constraints. Let mNumberOfConstraints = c ReDim mCosts(mNumberOfConstraints) 'Establish various properties of the constraints used here. ReDim mHopkinsDiacriticConstraint(mNumberOfConstraints) ReDim mCancelledConstraint(mNumberOfConstraints) ReDim mInviolableConstraint(mNumberOfConstraints) 'Open the Grammar.txt file. Let GrammarFile = FreeFile Open App.Path + "/input/Grammar.txt" For Input As #GrammarFile Do While Not EOF(GrammarFile) Line Input #GrammarFile, MyLine 'Grab the contents of the line: constraint name, whether it is used or not, and the weight. Let MyConstraint = Trim(s.Chomp(MyLine)) Let MyLine = s.Residue(MyLine) Let MyUsage = Trim(s.Chomp(MyLine)) Let MyLine = s.Residue(MyLine) Let MyWeight = Val(Trim(s.Chomp(MyLine))) 'Put these into the relevant program variables. Let mCosts(n(MyConstraint)) = MyWeight 'MsgBox "Assigning weight " + Str(MyWeight) + " to " + MyConstraint If LCase(MyUsage) = "unused" Then Let mCancelledConstraint(n(MyConstraint)) = True 'MsgBox "Cancelling " + MyConstraint ElseIf LCase(MyUsage) = "used" Then Let mCancelledConstraint(n(MyConstraint)) = False 'MsgBox "Entering " + MyConstraint + " in grammar" Else MsgBox "Please adjust your Grammar.txt file so that the middle column includes only the words " + Chr(34) + _ "used" + Chr(34) + " and " + Chr(34) + "unused" + Chr(34) + ", then restart the program." End End If Loop Close #GrammarFile 'This used to be hard-coded; so this code is now obsolete. 'Install the weights. The notation here uses the function n(), which permits mnemonic names to be ' used, hopefully averting programming errors and making the program easier to read. ' Costs of 1000 are deemed "inviolable" and are not printed out unless the user so requests. ' Let mCosts(n("MatchSW")) = 0.565922328493993 ' Let mCosts(n("MatchWS")) = 0 ' Let mCosts(n("FinalFall")) = 1000 ' Let mCosts(n("EmptyW")) = 0.543049224620714 ' Let mCosts(n("MedialEmptyW")) = 1 ' Let mCosts(n("NoClashEmpW")) = 0.904006913967139 ' Let mCosts(n("PostLEmpW")) = 7.07766618740575 ' Let mCosts(n("StrInW")) = 0 ' Let mCosts(n("WResol")) = 0 ' Let mCosts(n("SResol")) = 3.12044569608034 ' Let mCosts(n("ResolOutR")) = 9.65757018485208 ' Let mCosts(n("2SylInW")) = 1.838326586235 ' Let mCosts(n("3SylInW")) = 1.44503537750402 ' Let mCosts(n("4SylInW")) = 9.59702099606786E-02 ' Let mCosts(n("5SylInW")) = 1000 'We forgot to cancel this in submitted version -- adds 17 total candidates when violable. ' Let mCosts(n("StrlsInS")) = 1 ' Let mCosts(n("Outride")) = 2.19297407262521 ' Let mCosts(n("DoubleOutR")) = 0 ' Let mCosts(n("TripleOutR")) = 2.54962407099187 ' Let mCosts(n("Outride3")) = 0.833619411414047 ' Let mCosts(n("Outride4")) = 1 ' Let mCosts(n("LineInitOutR")) = 9.33623163749788 ' Let mCosts(n("OutRShortLine")) = 11.7768136796596 ' 'Let mCosts(n("Paraph")) = 0 ' Let mCosts(n("TriResol")) = 0.75932702453379 ' 'Now treated as inviolable, since all apparent violations involve level II prefixes. ' Let mCosts(n("Post1EmpW")) = 1000 ' Let mCosts(n("Post2EmpW")) = 0.722238996190378 ' Let mCosts(n("LightInS")) = 0.744343150874351 'We are giving some of the Hopkins constraints high costs. This is not circular, because they are included in ' the grammar. But they help us determine whether it will be necessary to overreave -- you would ' never overreave a syllable that rhymes, or is marked by Hopkins as requiring S or outride scansion. Let mCosts(n("HopRhyme")) = 20 Let mCosts(n("HopIncompatS")) = 20 Let mCosts(n("HopIncompatO")) = 20 'Constraints marked with cost > 1000 are inviolable. For ConstraintIndex = 1 To mNumberOfConstraints If mCosts(ConstraintIndex) >= 1000 Then Let mInviolableConstraint(ConstraintIndex) = True End If Next ConstraintIndex 'Constraints that track Hopkins's own preferences are also not included in the grammar per se. Let mHopkinsDiacriticConstraint(n("HopNoSupport")) = True Let mHopkinsDiacriticConstraint(n("HopIncompatS")) = True Let mHopkinsDiacriticConstraint(n("HopIncompatW")) = True Let mHopkinsDiacriticConstraint(n("HopIncompatO")) = True Let mHopkinsDiacriticConstraint(n("HopRhyme")) = True Let mHopkinsDiacriticConstraint(n("HopCaes")) = True 'We are canceling this constraint for the paper, because it is now in GEN. ' Let mCancelledConstraint(n("TriResol")) = True 'Our final model is quite a bit smaller and cancels a lot of constraints. ' Let mCancelledConstraint(n("StrInW")) = True ' Let mCancelledConstraint(n("FinalFall")) = True ' Let mCancelledConstraint(n("StrongYouth4")) = True ' Let mCancelledConstraint(n("StrongYouth5")) = True ' Let mCancelledConstraint(n("TheLife4")) = True ' Let mCancelledConstraint(n("TheLife5")) = True ' Let mCancelledConstraint(n("StrlsInS")) = True ' Let mCancelledConstraint(n("LightInS")) = True ' Let mCancelledConstraint(n("MatchWS")) = True ' Let mCancelledConstraint(n("EmptyW")) = True ' Let mCancelledConstraint(n("MedialEmptyW")) = True ' Let mCancelledConstraint(n("PostLEmpW")) = True ' Let mCancelledConstraint(n("Post2EmpW")) = True ' Let mCancelledConstraint(n("WResol")) = True ' Let mCancelledConstraint(n("ResolOutR")) = True ' Let mCancelledConstraint(n("TriResol")) = True ' Let mCancelledConstraint(n("2SylInFinalW")) = True ' Let mCancelledConstraint(n("4SylInW")) = True ' Let mCancelledConstraint(n("5SylInW")) = True ' Let mCancelledConstraint(n("DoubleOutR")) = True ' Let mCancelledConstraint(n("TripleOutR")) = True ' Let mCancelledConstraint(n("LineInitOutR")) = True ' Let mCancelledConstraint(n("Outride4")) = True ' Let mCancelledConstraint(n("NoOutride5")) = True ' 'But in some cases we want to see their violations anyway. If chkIncludeCancelledConstraints.Value = vbChecked Then For ConstraintIndex = 1 To mNumberOfConstraints Let mCancelledConstraint(ConstraintIndex) = False Next ConstraintIndex End If End Sub