Skip to content

Commit 70b6d17

Browse files
committed
Add PSLR runtime fallback and LAC support
1 parent d52a478 commit 70b6d17

6 files changed

Lines changed: 398 additions & 11 deletions

File tree

lib/lrama/output.rb

Lines changed: 189 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,19 @@ def pslr_function_declarations
424424

425425
if pslr_scanner_enabled?
426426
declarations << <<~C_CODE
427+
#ifndef YYPSLR_SCAN_RESULT_DEFINED
428+
# define YYPSLR_SCAN_RESULT_DEFINED
429+
typedef struct yypslr_scan_result {
430+
int token;
431+
int length;
432+
int is_layout;
433+
int is_character_token;
434+
} yypslr_scan_result;
435+
#endif
436+
437+
int yy_pseudo_scan_result (int parser_state, const char *input, yypslr_scan_result *result);
427438
int yy_pseudo_scan (int parser_state, const char *input, int *match_length);
439+
int yy_pslr_token_is_layout (int token);
428440
C_CODE
429441

430442
declarations << <<~C_CODE
@@ -435,6 +447,15 @@ def pslr_function_declarations
435447
# define YYPSLR_PSEUDO_SCAN_STATE(ParserState, Input, MatchLength) \\
436448
yy_pseudo_scan ((ParserState), (Input), (MatchLength))
437449
#endif
450+
451+
#ifndef YYPSLR_PSEUDO_SCAN_RESULT_STATE
452+
# define YYPSLR_PSEUDO_SCAN_RESULT_STATE(ParserState, Input, Result) \\
453+
yy_pseudo_scan_result ((ParserState), (Input), (Result))
454+
#endif
455+
456+
#ifndef YYPSLR_TOKEN_IS_LAYOUT
457+
# define YYPSLR_TOKEN_IS_LAYOUT(Token) yy_pslr_token_is_layout ((Token))
458+
#endif
438459
C_CODE
439460
end
440461

@@ -453,6 +474,13 @@ def pslr_function_declarations
453474
? YYPSLR_PSEUDO_SCAN_STATE (YYGETSTATE_CONTEXT (Context), (Input), (MatchLength)) \\
454475
: YYEMPTY)
455476
#endif
477+
478+
#ifndef YYPSLR_PSEUDO_SCAN_RESULT
479+
# define YYPSLR_PSEUDO_SCAN_RESULT(Context, Input, Result) \\
480+
((Context) != 0 \\
481+
? YYPSLR_PSEUDO_SCAN_RESULT_STATE (YYGETSTATE_CONTEXT (Context), (Input), (Result)) \\
482+
: YYEMPTY)
483+
#endif
456484
C_CODE
457485
end
458486

@@ -549,6 +577,20 @@ def token_pattern_token_ids_table
549577
lines << "static const int yy_token_pattern_to_token_id[YY_NUM_TOKEN_PATTERNS] = {"
550578
lines << " #{@context.states.token_patterns.map {|token_pattern| pslr_token_id(token_pattern) }.join(', ')}"
551579
lines << "};"
580+
lines << ""
581+
lines << "static const int yy_token_pattern_is_layout[YY_NUM_TOKEN_PATTERNS] = {"
582+
lines << " #{@context.states.token_patterns.map {|token_pattern| token_pattern.layout? ? 1 : 0 }.join(', ')}"
583+
lines << "};"
584+
lines << ""
585+
lines << "int"
586+
lines << "yy_pslr_token_is_layout (int token)"
587+
lines << "{"
588+
lines << " int i;"
589+
lines << " for (i = 0; i < YY_NUM_TOKEN_PATTERNS; i++)"
590+
lines << " if (yy_token_pattern_to_token_id[i] == token)"
591+
lines << " return yy_token_pattern_is_layout[i];"
592+
lines << " return 0;"
593+
lines << "}"
552594
lines.join("\n")
553595
end
554596

@@ -617,6 +659,14 @@ def scanner_accepts_table_code
617659
end
618660

619661
lines << "};"
662+
lines << ""
663+
lines << "static const int yy_scanner_fallback_accepts[YY_NUM_ACCEPTING_STATES] = {"
664+
fallback_row = pslr_accepting_states.map do |fsa_state|
665+
token = scanner_accepts.fallback_table[fsa_state.id]
666+
token ? token_pattern_indexes.fetch(token) : -1
667+
end
668+
lines << " #{fallback_row.join(', ')}"
669+
lines << "};"
620670
end
621671

622672
lines.join("\n")
@@ -651,6 +701,95 @@ def length_precedences_table_code
651701
lines.join("\n")
652702
end
653703

704+
def pslr_lac_function
705+
return "" unless pslr_enabled?
706+
707+
<<~C_CODE
708+
709+
static int
710+
yy_lac_check_ (yy_state_t *yyss, yy_state_t *yyssp, yysymbol_kind_t yytoken)
711+
{
712+
YYPTRDIFF_T yylac_len = yyssp - yyss + 1;
713+
yy_state_t *yylac_base = YY_CAST (yy_state_t *,
714+
YYMALLOC (YY_CAST (YYSIZE_T, YYMAXDEPTH * YYSIZEOF (yy_state_t))));
715+
yy_state_t *yylac_top;
716+
717+
if (!yylac_base)
718+
return 1;
719+
720+
if (YYMAXDEPTH < yylac_len)
721+
{
722+
YYFREE (yylac_base);
723+
return 1;
724+
}
725+
726+
YYCOPY (yylac_base, yyss, yylac_len);
727+
yylac_top = yylac_base + yylac_len - 1;
728+
729+
for (;;)
730+
{
731+
int yystate = *yylac_top;
732+
int yyn = yypact[yystate];
733+
734+
if (!yypact_value_is_default (yyn))
735+
{
736+
yyn += yytoken;
737+
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == yytoken)
738+
{
739+
yyn = yytable[yyn];
740+
if (0 < yyn)
741+
{
742+
YYFREE (yylac_base);
743+
return 1;
744+
}
745+
if (yytable_value_is_error (yyn))
746+
{
747+
YYFREE (yylac_base);
748+
return 0;
749+
}
750+
yyn = -yyn;
751+
}
752+
else
753+
{
754+
yyn = yydefact[yystate];
755+
if (yyn == 0)
756+
{
757+
YYFREE (yylac_base);
758+
return 0;
759+
}
760+
}
761+
}
762+
else
763+
{
764+
yyn = yydefact[yystate];
765+
if (yyn == 0)
766+
{
767+
YYFREE (yylac_base);
768+
return 0;
769+
}
770+
}
771+
772+
yylac_top -= yyr2[yyn];
773+
{
774+
const int yylhs = yyr1[yyn] - YYNTOKENS;
775+
const int yyi = yypgoto[yylhs] + *yylac_top;
776+
yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yylac_top
777+
? yytable[yyi]
778+
: yydefgoto[yylhs]);
779+
}
780+
781+
if (yylac_base + YYMAXDEPTH - 1 <= yylac_top)
782+
{
783+
YYFREE (yylac_base);
784+
return 1;
785+
}
786+
787+
*++yylac_top = YY_CAST (yy_state_t, yystate);
788+
}
789+
}
790+
C_CODE
791+
end
792+
654793
# Generate pseudo_scan function as C code
655794
def pseudo_scan_function
656795
return "" unless pslr_scanner_enabled?
@@ -666,27 +805,36 @@ def pseudo_scan_function
666805
* input: Input buffer pointer
667806
* match_length: Output parameter for matched length
668807
*
669-
* Returns: Selected parser token ID, or YYEMPTY if no match
808+
* Returns: Selected parser token ID. If neither the parser-state row
809+
* nor fallback row matches, returns YYUNDEF and consumes one byte.
670810
*/
671811
int
672-
yy_pseudo_scan(int parser_state, const char *input, int *match_length)
812+
yy_pseudo_scan_result (int parser_state, const char *input, yypslr_scan_result *result)
673813
{
674-
int local_match_length = 0;
675814
int ss = 0; /* FSA initial state */
676815
int ibest = 0;
677816
int pbest = YY_PSLR_EMPTY_PATTERN;
817+
int fallback_ibest = 0;
818+
int fallback_pbest = YY_PSLR_EMPTY_PATTERN;
678819
int i = 0;
679820
680-
if (match_length == NULL) {
681-
match_length = &local_match_length;
821+
if (result == NULL) {
822+
return YYEMPTY;
682823
}
683824
684-
*match_length = 0;
825+
result->token = YYEMPTY;
826+
result->length = 0;
827+
result->is_layout = 0;
828+
result->is_character_token = 0;
685829
686830
if (parser_state < 0 || parser_state >= YY_NUM_PARSER_STATES || input == NULL) {
687831
return YYEMPTY;
688832
}
689833
834+
if (input[0] == '\\0') {
835+
return YYEMPTY;
836+
}
837+
690838
while (input[i] != '\\0') {
691839
int c = (unsigned char)input[i];
692840
int next_ss = yy_scanner_transition[ss][c];
@@ -709,15 +857,46 @@ def pseudo_scan_function
709857
ibest = i;
710858
}
711859
}
860+
861+
pattern_index = yy_scanner_fallback_accepts[sa];
862+
if (pattern_index != YY_PSLR_EMPTY_PATTERN) {
863+
fallback_pbest = pattern_index;
864+
fallback_ibest = i;
865+
}
712866
}
713867
}
714868
715-
*match_length = ibest;
716-
if (pbest == YY_PSLR_EMPTY_PATTERN) {
717-
return YYEMPTY;
869+
if (pbest != YY_PSLR_EMPTY_PATTERN) {
870+
result->token = yy_token_pattern_to_token_id[pbest];
871+
result->length = ibest;
872+
result->is_layout = yy_token_pattern_is_layout[pbest];
873+
return result->token;
874+
}
875+
876+
if (fallback_pbest != YY_PSLR_EMPTY_PATTERN) {
877+
result->token = yy_token_pattern_to_token_id[fallback_pbest];
878+
result->length = fallback_ibest;
879+
result->is_layout = yy_token_pattern_is_layout[fallback_pbest];
880+
return result->token;
881+
}
882+
883+
result->token = YYUNDEF;
884+
result->length = 1;
885+
result->is_character_token = 1;
886+
return result->token;
887+
}
888+
889+
int
890+
yy_pseudo_scan(int parser_state, const char *input, int *match_length)
891+
{
892+
yypslr_scan_result result;
893+
int token = yy_pseudo_scan_result (parser_state, input, &result);
894+
895+
if (match_length != NULL) {
896+
*match_length = result.length;
718897
}
719898
720-
return yy_token_pattern_to_token_id[pbest];
899+
return token;
721900
}
722901
C_CODE
723902
end
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
%option noinput nounput noyywrap never-interactive
2+
3+
%{
4+
#include <stdio.h>
5+
#include "pslr_template_argument_lists.h"
6+
7+
#define YY_DECL int yylex(YYSTYPE *yylval, struct parse_params *p)
8+
%}
9+
10+
%%
11+
12+
(.|\n)+ {
13+
yypslr_scan_result result;
14+
int token;
15+
16+
(void)yylval;
17+
token = YYPSLR_PSEUDO_SCAN_RESULT(p, yytext, &result);
18+
if (result.length <= 0) {
19+
result.length = 1;
20+
}
21+
if (result.length < yyleng) {
22+
yyless(result.length);
23+
}
24+
if (result.is_layout) {
25+
return yylex(yylval, p);
26+
}
27+
return token;
28+
}
29+
30+
<<EOF>> {
31+
return YYEOF;
32+
}
33+
34+
%%

0 commit comments

Comments
 (0)